java基础学习_面向对象(下)02_day09总结
2018-02-16 23:48
441 查看
=============================================================================
=============================================================================
涉及的知识点有:
1:final关键字(掌握)
2:多态(掌握)
3:抽象类(掌握)
4:接口(掌握)
=============================================================================
=============================================================================
1:final关键字(掌握)
(0)由于继承中方法有一个现象:方法重写。
所以,父类的功能,就会被子类给覆盖掉。
有些时候,我们不想让子类去覆盖掉父类的功能,只能调用但不能去覆盖修改。
这个时候,针对这种情况,Java就提供了一个关键字:final。
---------------------------------------
(1)final是最终的意思,常见的final可以修饰类、方法、变量。
(2)fianl的特点:
A:final修饰的类,不能被继承。
编译报错:无法从最终Fu进行继承
应用:最底层的那个类可以用final修饰,这样该类就不能有儿子了。(即绝育)
B:final修饰的方法,不能被重写(覆盖/复写)。
编译报错:Zi中的show()无法覆盖Fu中的show()
C:final修饰的变量,是一个常量,只能被赋值一次。
编译报错:无法为最终变量num2分配值
注意:被final修饰的成员变量没有默认值,必须在构造器(constructor )结束之前被赋予一个明确的值。即在定义被final修饰的成员变量时就给值。
小补充:
常量分为两种:
1.字面值常量
例如:"hello"、10、true
2.自定义常量
例如:final int x = 10;
---------------------------------------
(3)final关键字面试题相关:
public、private等权限修饰符会用来修饰成员变量、构造方法和成员方法。
不会用来修饰局部变量(在方法内部的变量),因为权限修饰符修饰局部变量是没有意义的,在方法内部的局部变量是被封装好的,外界的方法看不到。
final既可以修饰局部变量也可以修饰成员变量和成员方法。
A:final修饰局部变量
a:当局部变量为基本数据类型 值不能发生改变
final x = 100;
b:当局部变量为引用数据类型 地址值不能发生改变,但是该对象的堆内存的内容是可以改变的。
final Student s = new Student();
s = new Student(); //对象s重新指向了新的地址值,但是对象s被final修饰了,所以这句会报错!
---------------------------------------
B:final修的饰变量的初始化时机
a:被final修饰的变量只能被初始化一次(默认初始化不算哦)。
b:被final修饰的变量的初始化时机:在对象构造方法执行完毕前进行赋值就行。
注意:这个时机仅仅针对的是非静态的常量。因为静态的早早就加载了。
c:变量常见的给值时机
1.在定义的时候就给值。(推荐方式)
2.在构造代码块中给值。
3.在构造方法中给值。
-----------------------------------------------------------------------------
2:多态(掌握)
(1)某一个事物,在不同时刻表现出来的不同状态。
猫可以是猫的类型。
猫 m = new 猫();
同时猫也是动物的一种,也可以把猫称为动物。
动物 d = new 猫();
再举一个例子:水在不同时刻的状态。
---------------------------------------
(2)多态的前提和体现:
A:多态有继承或者实现关系。
B:多态有方法重写。(因为多态是靠方法重写来体现不同状态的)
其实没有方法重写也是可以的,但是如果没有方法重写就没有意义了。
C:多态有父类或者父接口引用指向子类对象。
即:父 f = new 子();
多态的分类:
a:具体类的多态
class Fu {}
class Zi extends Fu {}
Fu f = new Zi();
b:抽象类的多态
abstract class Fu {}
class Zi extends Fu {}
Fu f = new Zi();
c:接口的多态
interface Fu {}
class Zi implements Fu {}
Fu f = new Zi();
---------------------------------------
(3)多态中的成员访问特点:
A:对于多态中的成员变量的访问
编译看左边,运行看左边。
因为子可以访问父的成员变量,父不可以访问子的成员变量。(即:对于成员变量,可以向上访问,不可以向下访问。)
B:对于多态中的构造方法的访问
创建子类对象的时候,子类的构造都会默认访问父类构造,为了对父类的数据进行初始化。
C:对于多态中的成员方法的访问
编译看左边,运行看右边。
因为成员方法有重写,父类的成员方法会被子类覆盖掉。因为成员方法是跟对象相关的。
D:对于多态中的静态方法的访问
编译看左边,运行看左边。
因为静态方法只能被静态方法重写,但是静态方法根本算不上重写。因为静态是跟类相关的。所以访问静态方法的时候是左边。
为什么?
因为成员方法有方法重写,父类的动作被子类重写掉了,所以该动作走的是儿子的。
也即对于多态中的成员方法的访问看右边(子类)。
---------------------------------------
(4)多态的好处:
A:提高了代码的维护性(继承体现)
因为多态有继承或者实现关系。
B:提高了代码的扩展性(多态体现)
原因如下:
猫狗案例:
注意几点:
测试类里面不能放其他东西,只能放创建的对象和通过对象调用的方法。
把构造方法私有,别人就不能创建对象了,只能通过类名来调用静态方法了。
针对动物操作的工具类中,调用动物的功能时,形参用动物类进行接收(即多态)。
即 Animal a = new Cat();
a = new Dog();
a = new Pig();
......
---------------------------------------
(5)多态的弊端:
Fu f = new Zi();
父类不能使用子类的特有功能(即成员方法)。
因为我们拿父类去访问子类,但是对于成员方法,父类只能访问在父类中定义的方法,在父类中没有定义的方法不能访问。
简言之:子可以当做父使用,父不能当做子使用。因为子比父的东西要多。
我父类就想使用子类的特有功能?行不行?
答:行。
那怎么行呢?
法一:创建子类对象调用方法即可。(可以,但是很多时候不合理。而且,重新创建对象,太占内存了。)
Zi z = new Zi();
法二:把父类的引用强制赋值给子类的引用。(向下转型)(这样做内存中只有一个对象,省内存!)
因为引用类型赋值要求类型要兼容!
Zi z = (Zi)f;
---------------------------------------
(6)多态中的转型问题:
A:向上转型
从子到父
Fu f = new Zi();
B:向下转型
从父到子
Zi z = (Zi)f; //前提:要求该f必须是能够转换为Zi的。
---------------------------------------
(7)孔子装爹的案例帮助大家理解多态
//然后就穿上爹的衣服,带上爹的眼睛,粘上爹的胡子。就开始装爹。
//其实就是向上转型。
孔子爹 k爹 = new 孔子();
//脱下爹的装备,换上自己的装备。
//其实就是向下转型。
孔子 k = (孔子)k爹;
---------------------------------------
(8)多态的练习
A:猫狗案例
B:老师和学生案例
-----------------------------------------------------------------------------
3:抽象类(掌握)
(1)抽象类的概述:
把多个共性的东西提取到一个类中,这是继承的做法。
但是呢,这多个共性的东西,在有些时候,方法声明是一样的,但是方法体不一样。
也就是说,方法声明是一样,但是每个具体的对象在具体实现的时候内容不一样。
所以,我们在定义这些共性的方法的时候,就不能给出具体的方法体。
在Java中,一个没有具体的方法体的方法应该定义为抽象方法。
而在一个类中如果有抽象方法,该类必须定义为抽象类。
---------------------------------------
(2)抽象类的特点:
A:抽象类和抽象方法必须用关键字abstract修饰。
格式:
abstract class 类名 {}
public abstract void eat(); //没有方法体。
//public abstract void eat() {} //有方法体,但方法体为空。会报错。
B:抽象类中不一定有抽象方法,但是有抽象方法的类一定是抽象类。
C:抽象类不能实例化。
例如:
abstract class Animal {}
Animal a = new Animal(); //会报错,因为动物类是抽象的,不能new。
抽象类有构造方法,但是不能实例化。
那么抽象类的构造方法的作用是什么呢?
答:用于子类访问父类数据初始化。
D:抽象类的子类可能是:
a:抽象类的子类可以是一个抽象类。这个子类不用重写抽象类中的抽象方法。
b:抽象类的子类可以是一个具体类(可以new对象,使用多态实例化抽象类)。但这个子类必须重写抽象类中的所有抽象方法。
E:抽象类的实例化
通过具体的子类实现的(即:多态的方式。也即:向上转型的方式),其实这也是多态的一种,叫做抽象类多态。
多态最主要的应用是在抽象类中使用,而不是在具体类中。这样抽象类对外界提供的是抽象的方法,而靠真正具体的子类来重写实现的。
---------------------------------------
(3)抽象类的成员特点:
A:抽象类的成员变量的特点
可以有变量
也可以有常量
B:抽象类的构造方法的特点
有构造方法,但是不能实例化。用于子类访问父类数据的初始化。
C:抽象类的成员方法的特点
可以有抽象方法 强制具体的子类必须完成某些动作。
也可以有非抽象方法 使子类继承非抽象方法,提高代码复用性。
---------------------------------------
(4)抽象类的练习:
A:猫狗案例练习
示例代码如下:
B:老师案例练习
示例代码如下:
C:学生案例练习
示例代码如下:类同B,不在赘述。
D:员工案例练习
示例代码如下:
---------------------------------------
(5)抽象类的几个小问题
A:抽象类有构造方法,但是抽象类不能实例化,那么构造方法有什么用?
答:用于子类访问父类数据的初始化。
B:一个类如果没有抽象方法,却定义为抽象类,有什么用?
答:为了不让外界创建该抽象类的对象,要想访问它只能通过该抽象类的子类。
C:abstract不能和哪些关键字共存?
a:final 冲突 因为最终方法不能被重写,而抽象的方法需要被具体的子类重写。
final abstract void show(); //错误: 非法的修饰符组合: abstract和private
b:private 冲突 因为私有方法不能被继承,所以就不能被重写,而抽象的方法需要被具体的子类重写。
private abstract void show(); //错误: 非法的修饰符组合: abstract和final
c:static 无意义 因为抽象方法是没有方法体的,而静态是可以直接通过类名访问的。访问一个没有方法体的方法,意义何在呢?
static abstract void show(); //错误: 非法的修饰符组合: abstract和static
-----------------------------------------------------------------------------
4:接口(掌握)
(1)回顾猫狗案例,它们仅仅提供一些基本功能。
部分的猫会钻火圈,狗会跳高等功能,不是动物本身就具备的,
是在后面的培养中训练出来的,所以,为了体现事物功能的扩展性,
Java中就提供了接口来定义这些额外功能,并不给出具体实现(说明是抽象方法),将来哪些猫狗需要被培训,只需要这部分猫狗把这些额外功能实现即可。
其实接口是最最抽象的抽象类。
---------------------------------------
(2)接口的特点:
A:接口用关键字interface修饰
interface 接口名 {}
B:类实现接口用implements修饰
class 类名 implements 接口名 {}
C:接口不能实例化
那么,接口如何实例化呢?
按照多态的方式来实例化。(即就要去做一个具体的子类,通过具体的子类去实例化)
由此可见,多态有几种方式:
1.具体类多态(几乎没有,但是讲解是通过具体类讲解的)
2.抽象类多态(常用)
3.接口多态(最常用)
D:接口的实现类(子类)
接口的实现类格式:接口名+Impl
a:接口的实现类是一个抽象类。但是意义不大,因为你是抽象类,最终还得需要具体子类。
//定义动物培训接口
interface AnimalTrain {
public abstract void jump();
}
//抽象类实现接口
abstract class Dog implements AnimalTrain {
}
b:接口的实现类是一个具体类,这个类必须重写接口中的所有抽象方法。(推荐方案)
//定义动物培训接口
interface AnimalTrain {
public abstract void jump();
}
//具体类实现接口
class Cat implements AnimalTrain {
public void jump() {
System.out.println("猫可以跳高了");
}
}
---------------------------------------
(3)接口的成员特点:
A:接口的成员变量特点:
只能是常量,并且是静态的。
因为接口的所有成员变量的默认修饰符都是:public static final
建议自己手动给出。
B:接口的构造方法特点:
接口没有构造方法 。
那么接口的实现类的无参构造方法默认访问的是谁的无参构造呢?
答:所有的类都默认继承一个类:Object类。
因为:类 Object 是类层次结构的根类。每个类都使用 Object 作为超类。
又因为:类 Object 只有无参构造方法,所以后来要求所有子类都默认调用的是父类的无参构造方法。
//接口名+Impl这种格式是接口的实现类格式
/*
class InterImpl implements Inter {
public InterImpl() {
super();
}
}
*/
//上面的写法等价于下面的写法
class InterImpl extends Object implements Inter {
public InterImpl() {
super();
}
}
C:接口的成员方法特点:
接口的成员方法只能是抽象的。
因为接口的所有成员方法的默认修饰符都是:public abstract
建议自己手动给出。
---------------------------------------
(4)类与类、类与接口、接口与接口的关系
A:类与类的关系
继承关系,只能单继承,不能多继承(只有一个父类),可以多层继承(可以有爷爷)。
class Son extends Father {} //正确
class Son extends Father, Mother {} //错误
B:类与接口的关系
1.实现关系,可以单实现,也可以多实现。(可以多扩展嘛)
2.还可以在继承一个类的同时,实现多个接口。(继承类 Object 嘛)
class Son implements Father, Mother {} //正确
class Son extends Object implements Father, Mother {} //正确
C:接口与接口的关系
继承关系,可以单继承,也可以多继承。
小结:Java中的类是单继承的,Java中的接口可以多继承。
---------------------------------------
(5)抽象类和接口的区别(自己补齐)?
A:成员区别
抽象类:
成员变量:可以有变量,也可以有常量
构造方法:有(用于子类访问父类数据的初始化)
成员方法:可以有抽象方法,也可以有非抽象方法
接口:
成员变量:只可以是常量
构造方法:无
成员方法:只可以是抽象方法
B:关系区别:
类与类:
继承关系,只能单继承和多层继承。
类与接口:
实现关系,可以单实现,也可以多实现。
接口与接口:
继承关系,可以单继承,也可以多继承。
C:设计理念不同
抽象类 被继承体现的是:“is a”的关系,抽象类中定义的是共性功能。
接口 被实现体现的是:“like a”的关系,接口中定义的是扩展功能。
---------------------------------------
(6)接口练习:
A:猫狗案例,加入跳高功能
共有六个类:(这里将接口理解为最最抽象的类)
跳高接口
动物类
猫类
狗类
有跳高功能的猫类
有跳高功能的狗类
测试类
示例代码如下:
B:老师和学生案例,加入抽烟功能
共有六个类:(这里将接口理解为最最抽象的类)
抽烟接口
人类
学生类
老师类
有抽功能的学生类
有抽功能的老师类
测试类
示例代码同上,不在赘述!
=============================================================================
=============================================================================
涉及的知识点有:
1:final关键字(掌握)
2:多态(掌握)
3:抽象类(掌握)
4:接口(掌握)
=============================================================================
=============================================================================
1:final关键字(掌握)
(0)由于继承中方法有一个现象:方法重写。
所以,父类的功能,就会被子类给覆盖掉。
有些时候,我们不想让子类去覆盖掉父类的功能,只能调用但不能去覆盖修改。
这个时候,针对这种情况,Java就提供了一个关键字:final。
---------------------------------------
(1)final是最终的意思,常见的final可以修饰类、方法、变量。
(2)fianl的特点:
A:final修饰的类,不能被继承。
编译报错:无法从最终Fu进行继承
应用:最底层的那个类可以用final修饰,这样该类就不能有儿子了。(即绝育)
B:final修饰的方法,不能被重写(覆盖/复写)。
编译报错:Zi中的show()无法覆盖Fu中的show()
C:final修饰的变量,是一个常量,只能被赋值一次。
编译报错:无法为最终变量num2分配值
注意:被final修饰的成员变量没有默认值,必须在构造器(constructor )结束之前被赋予一个明确的值。即在定义被final修饰的成员变量时就给值。
小补充:
常量分为两种:
1.字面值常量
例如:"hello"、10、true
2.自定义常量
例如:final int x = 10;
---------------------------------------
(3)final关键字面试题相关:
public、private等权限修饰符会用来修饰成员变量、构造方法和成员方法。
不会用来修饰局部变量(在方法内部的变量),因为权限修饰符修饰局部变量是没有意义的,在方法内部的局部变量是被封装好的,外界的方法看不到。
final既可以修饰局部变量也可以修饰成员变量和成员方法。
A:final修饰局部变量
a:当局部变量为基本数据类型 值不能发生改变
final x = 100;
b:当局部变量为引用数据类型 地址值不能发生改变,但是该对象的堆内存的内容是可以改变的。
final Student s = new Student();
s = new Student(); //对象s重新指向了新的地址值,但是对象s被final修饰了,所以这句会报错!
---------------------------------------
B:final修的饰变量的初始化时机
a:被final修饰的变量只能被初始化一次(默认初始化不算哦)。
b:被final修饰的变量的初始化时机:在对象构造方法执行完毕前进行赋值就行。
注意:这个时机仅仅针对的是非静态的常量。因为静态的早早就加载了。
c:变量常见的给值时机
1.在定义的时候就给值。(推荐方式)
2.在构造代码块中给值。
3.在构造方法中给值。
-----------------------------------------------------------------------------
2:多态(掌握)
(1)某一个事物,在不同时刻表现出来的不同状态。
猫可以是猫的类型。
猫 m = new 猫();
同时猫也是动物的一种,也可以把猫称为动物。
动物 d = new 猫();
再举一个例子:水在不同时刻的状态。
---------------------------------------
(2)多态的前提和体现:
A:多态有继承或者实现关系。
B:多态有方法重写。(因为多态是靠方法重写来体现不同状态的)
其实没有方法重写也是可以的,但是如果没有方法重写就没有意义了。
C:多态有父类或者父接口引用指向子类对象。
即:父 f = new 子();
多态的分类:
a:具体类的多态
class Fu {}
class Zi extends Fu {}
Fu f = new Zi();
b:抽象类的多态
abstract class Fu {}
class Zi extends Fu {}
Fu f = new Zi();
c:接口的多态
interface Fu {}
class Zi implements Fu {}
Fu f = new Zi();
---------------------------------------
(3)多态中的成员访问特点:
A:对于多态中的成员变量的访问
编译看左边,运行看左边。
因为子可以访问父的成员变量,父不可以访问子的成员变量。(即:对于成员变量,可以向上访问,不可以向下访问。)
B:对于多态中的构造方法的访问
创建子类对象的时候,子类的构造都会默认访问父类构造,为了对父类的数据进行初始化。
C:对于多态中的成员方法的访问
编译看左边,运行看右边。
因为成员方法有重写,父类的成员方法会被子类覆盖掉。因为成员方法是跟对象相关的。
D:对于多态中的静态方法的访问
编译看左边,运行看左边。
因为静态方法只能被静态方法重写,但是静态方法根本算不上重写。因为静态是跟类相关的。所以访问静态方法的时候是左边。
为什么?
因为成员方法有方法重写,父类的动作被子类重写掉了,所以该动作走的是儿子的。
也即对于多态中的成员方法的访问看右边(子类)。
---------------------------------------
(4)多态的好处:
A:提高了代码的维护性(继承体现)
因为多态有继承或者实现关系。
B:提高了代码的扩展性(多态体现)
原因如下:
猫狗案例:
注意几点:
测试类里面不能放其他东西,只能放创建的对象和通过对象调用的方法。
把构造方法私有,别人就不能创建对象了,只能通过类名来调用静态方法了。
针对动物操作的工具类中,调用动物的功能时,形参用动物类进行接收(即多态)。
即 Animal a = new Cat();
a = new Dog();
a = new Pig();
......
---------------------------------------
(5)多态的弊端:
Fu f = new Zi();
父类不能使用子类的特有功能(即成员方法)。
因为我们拿父类去访问子类,但是对于成员方法,父类只能访问在父类中定义的方法,在父类中没有定义的方法不能访问。
简言之:子可以当做父使用,父不能当做子使用。因为子比父的东西要多。
我父类就想使用子类的特有功能?行不行?
答:行。
那怎么行呢?
法一:创建子类对象调用方法即可。(可以,但是很多时候不合理。而且,重新创建对象,太占内存了。)
Zi z = new Zi();
法二:把父类的引用强制赋值给子类的引用。(向下转型)(这样做内存中只有一个对象,省内存!)
因为引用类型赋值要求类型要兼容!
Zi z = (Zi)f;
---------------------------------------
(6)多态中的转型问题:
A:向上转型
从子到父
Fu f = new Zi();
B:向下转型
从父到子
Zi z = (Zi)f; //前提:要求该f必须是能够转换为Zi的。
---------------------------------------
(7)孔子装爹的案例帮助大家理解多态
//然后就穿上爹的衣服,带上爹的眼睛,粘上爹的胡子。就开始装爹。
//其实就是向上转型。
孔子爹 k爹 = new 孔子();
//脱下爹的装备,换上自己的装备。
//其实就是向下转型。
孔子 k = (孔子)k爹;
---------------------------------------
(8)多态的练习
A:猫狗案例
B:老师和学生案例
-----------------------------------------------------------------------------
3:抽象类(掌握)
(1)抽象类的概述:
把多个共性的东西提取到一个类中,这是继承的做法。
但是呢,这多个共性的东西,在有些时候,方法声明是一样的,但是方法体不一样。
也就是说,方法声明是一样,但是每个具体的对象在具体实现的时候内容不一样。
所以,我们在定义这些共性的方法的时候,就不能给出具体的方法体。
在Java中,一个没有具体的方法体的方法应该定义为抽象方法。
而在一个类中如果有抽象方法,该类必须定义为抽象类。
---------------------------------------
(2)抽象类的特点:
A:抽象类和抽象方法必须用关键字abstract修饰。
格式:
abstract class 类名 {}
public abstract void eat(); //没有方法体。
//public abstract void eat() {} //有方法体,但方法体为空。会报错。
B:抽象类中不一定有抽象方法,但是有抽象方法的类一定是抽象类。
C:抽象类不能实例化。
例如:
abstract class Animal {}
Animal a = new Animal(); //会报错,因为动物类是抽象的,不能new。
抽象类有构造方法,但是不能实例化。
那么抽象类的构造方法的作用是什么呢?
答:用于子类访问父类数据初始化。
D:抽象类的子类可能是:
a:抽象类的子类可以是一个抽象类。这个子类不用重写抽象类中的抽象方法。
b:抽象类的子类可以是一个具体类(可以new对象,使用多态实例化抽象类)。但这个子类必须重写抽象类中的所有抽象方法。
E:抽象类的实例化
通过具体的子类实现的(即:多态的方式。也即:向上转型的方式),其实这也是多态的一种,叫做抽象类多态。
多态最主要的应用是在抽象类中使用,而不是在具体类中。这样抽象类对外界提供的是抽象的方法,而靠真正具体的子类来重写实现的。
---------------------------------------
(3)抽象类的成员特点:
A:抽象类的成员变量的特点
可以有变量
也可以有常量
B:抽象类的构造方法的特点
有构造方法,但是不能实例化。用于子类访问父类数据的初始化。
C:抽象类的成员方法的特点
可以有抽象方法 强制具体的子类必须完成某些动作。
也可以有非抽象方法 使子类继承非抽象方法,提高代码复用性。
---------------------------------------
(4)抽象类的练习:
A:猫狗案例练习
示例代码如下:
/* 猫狗案例练习: 具体事物:猫,狗 共性:姓名,年龄,吃饭 --------------------------------------- 分析:从具体到抽象 猫类: 成员变量:姓名,年龄 构造方法:无参,带参 成员方法:吃饭(猫吃鱼) 狗类: 成员变量:姓名,年龄 构造方法:无参,带参 成员方法:吃饭(狗吃肉) 因为有共性的内容,所以就提取了一个父类。动物类。 但是又由于吃饭的内容不一样,所以吃饭的方法是抽象的, 而方法是抽象的,则类就必须定义为抽象类。得到抽象动物类。 抽象动物类: 成员变量:姓名,年龄 构造方法:无参,带参 成员方法:吃饭(); --------------------------------------- 实现:从抽象到具体 抽象动物类: 成员变量:姓名,年龄 构造方法:无参,带参 成员方法:吃饭(); 具体的狗类: 继承自抽象动物类 重写吃饭(); 具体的猫类: 继承自抽象动物类 重写吃饭(); 测试类: */ //定义抽象的动物类 abstract class Animal { //姓名 private String name; //年龄 private int age; public Animal() {} public Animal(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } //定义一个抽象的方法 public abstract void eat(); } //定义具体的狗类 class Dog extends Animal { public Dog() {} public Dog(String name, int age) { super(name, age); } public void eat() { System.out.println("狗吃肉"); } } //定义具体的猫类 class Cat extends Animal { public Cat() {} public Cat(String name, int age) { super(name, age); } public void eat() { System.out.println("猫吃鱼"); } } //测试类 class AbstractTest { public static void main(String[] args) { //测试狗类 //具体类测试 //方式1: Dog d = new Dog(); d.setName("旺财"); d.setAge(3); System.out.println(d.getName()+"---"+d.getAge()); d.eat(); //方式2: Dog d2 = new Dog("旺财", 3); System.out.println(d2.getName()+"---"+d2.getAge()); d2.eat(); System.out.println("---------------------------"); //多态测试:因为子类中没有定义特有功能,所以可以多态实现。 Animal a = new Dog(); a.setName("旺财"); a.setAge(3); System.out.println(a.getName()+"---"+a.getAge()); a.eat(); Animal a2 = new Dog("旺财", 3); System.out.println(a2.getName()+"---"+a2.getAge()); a2.eat(); System.out.println("---------------------------"); //练习:测试猫类 //具体类测试 //方式一: Cat c = new Cat(); c.setName("多啦A梦"); c.setAge(5); System.out.println(c.getName()+"---"+c.getAge()); c.eat(); //方式二: Cat c2 = new Cat("哆啦A梦", 5); System.out.println(c2.getName()+"---"+c2.getAge()); c2.eat(); System.out.println("---------------------------"); //多态测试:因为子类中没有定义特有功能,所以可以多态实现。 Animal a3 = new Cat(); a3.setName("哆啦A梦"); a3.setAge(5); System.out.println(a3.getName()+"---"+a3.getAge()); a3.eat(); Animal a4 = new Cat("哆啦A梦", 5); System.out.println(a4.getName()+"---"+a4.getAge()); a4.eat(); } }
B:老师案例练习
示例代码如下:
/* 老师案例练习: 具体事物:基础班老师,就业班老师 共性:姓名,年龄,讲课 --------------------------------------- 分析: 基础班老师类 姓名,年龄 无参,带参 讲课(讲解JavaSE) 就业班老师类 姓名,年龄 无参,带参 讲课(讲解JavaEE) 抽象老师类 姓名,年龄 无参,带参 讲课(); --------------------------------------- 实现: 抽象老师类 具体的基础班老师类 具体的就业班老师类 测试类 */ //定义抽象的老师类 abstract class Teacher { //姓名 private String name; //年龄 private int age; public Teacher() {} public Teacher(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } //抽象方法 public abstract void teach(); } //具体的基础班老师类 class BasicTeacher extends Teacher { public BasicTeacher(){} public BasicTeacher(String name, int age) { super(name, age); } public void teach() { System.out.println("基础班老师讲解JavaSE"); } } //具体的就业班老师类 class WorkTeacher extends Teacher { public WorkTeacher(){} public WorkTeacher(String name, int age) { super(name, age); } public void teach() { System.out.println("就业班老师讲解JavaEE"); } } class AbstractTest2 { public static void main(String[] args) { //具体的类测试,自己玩 //基础班老师 //方式一: BasicTeacher bt = new BasicTeacher(); bt.setName("刘意"); bt.setAge(30); System.out.println(bt.getName()+"---"+bt.getAge()); bt.teach(); //方式二: bt = new BasicTeacher("刘意", 30); System.out.println(bt.getName()+"---"+bt.getAge()); bt.teach(); System.out.println("--------------"); //就业班老师 //方式一: WorkTeacher wt = new WorkTeacher(); wt.setName("林青霞"); wt.setAge(27); System.out.println(wt.getName()+"---"+wt.getAge()); wt.teach(); //方式二: wt = new WorkTeacher("林青霞", 27); System.out.println(wt.getName()+"---"+wt.getAge()); wt.teach(); System.out.println("---------------"); //多态测试:因为子类中没有定义特有功能,所以可以多态实现。 //基础班老师 Teacher t = new BasicTeacher(); System.out.println(t);//BasicTeacher@6d06d69c t.setName("刘意"); t.setAge(30); System.out.println(t.getName()+"---"+t.getAge()); t.teach(); System.out.println("--------------"); //对象名没有改哦,因为这是同一个对象此时指向了别的地址。 t = new BasicTeacher("刘意", 30); System.out.println(t);//BasicTeacher@7852e922 System.out.println(t.getName()+"---"+t.getAge()); t.teach(); System.out.println("--------------"); //就业班老师 //对象名依旧没有改哦,因为这是同一个对象此时指向了别的地址。 t = new WorkTeacher(); System.out.println(t);//WorkTeacher@4e25154f t.setName("林青霞"); t.setAge(27); System.out.println(t.getName()+"---"+t.getAge()); t.teach(); System.out.println("--------------"); //对象名依旧依旧没有改哦,因为这是同一个对象此时指向了别的地址。 t = new WorkTeacher("林青霞", 27); System.out.println(t);//WorkTeacher@70dea4e System.out.println(t.getName()+"---"+t.getAge()); t.teach(); } }
C:学生案例练习
示例代码如下:类同B,不在赘述。
D:员工案例练习
示例代码如下:
/* 假如我们在开发一个系统时需要对员工类进行设计,员工包含3个属性:姓名、工号以及工资。 经理也是员工,除了含有员工的属性外,另为还有一个奖金属性。 请使用继承的思想设计出员工类和经理类。要求类中提供必要的方法进行属性访问。 --------------------------------------- 分析: 普通员工类 成员变量:姓名、工号以及工资。 成员方法:工作 经理类: 成员变量:姓名、工号以及工资,奖金属性。 成员方法:工作 --------------------------------------- 实现: 抽象员工类 具体的普通员工类 具体的经理类 测试类 */ //定义抽象员工类 abstract class Employee { //姓名、工号以及工资 private String name; private String id; private int salary; public Employee() {} public Employee(String name, String id, int salary) { this.name = name; this.id = id; this.salary = salary; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getId() { return id; } public void setId(String id) { this.id = id; } public int getSalary() { return salary; } public void setSalary(int salary) { this.salary = salary; } //工作 public abstract void work(); } //具体的普通员工类 class Programmer extends Employee { public Programmer() {} public Programmer(String name, String id, int salary) { super(name, id, salary); } public void work() { System.out.println("按照需求写代码"); } } //具体的经理类 class Manager extends Employee { //奖金 private int money; //bonus 奖金 public Manager() {} public Manager(String name, String id, int salary, int money) { super(name, id, salary); this.money = money; } public void work() { System.out.println("跟客户谈需求"); } public int getMoney() { return money; } public void setMoney(int money) { this.money = money; } } //测试类 class AbstractTest4 { public static void main(String[] args) { //测试具体的普通员工类 Employee emp = new Programmer(); emp.setName("林青霞"); emp.setId("czbk001"); emp.setSalary(18000); System.out.println(emp.getName()+"---"+emp.getId()+"---"+emp.getSalary()); emp.work(); System.out.println("-------------"); emp = new Programmer("林青霞", "czbk001", 18000); System.out.println(emp.getName()+"---"+emp.getId()+"---"+emp.getSalary()); emp.work(); System.out.println("-------------"); //测试具体的经理类 /* emp = new Manager(); emp.setName("刘意"); emp.setId("czbk002"); emp.setSalary(8000); emp.setMoney(2000); */ //由于子类经理类有特有的内容-成员变量-奖金,用多态(父类)测试不合适,所以我们用具体的子类来测试。 Manager m = new Manager(); m.setName("刘意"); m.setId("czbk002"); m.setSalary(8000); m.setMoney(2000); System.out.println(m.getName()+"---"+m.getId()+"---"+m.getSalary()+"---"+m.getMoney()); m.work(); System.out.println("-------------"); //通过含参构造方法赋值 m = new Manager("刘意", "czbk002", 8000, 2000); System.out.println(m.getName()+"---"+m.getId()+"---"+m.getSalary()+"---"+m.getMoney()); m.work(); } }
---------------------------------------
(5)抽象类的几个小问题
A:抽象类有构造方法,但是抽象类不能实例化,那么构造方法有什么用?
答:用于子类访问父类数据的初始化。
B:一个类如果没有抽象方法,却定义为抽象类,有什么用?
答:为了不让外界创建该抽象类的对象,要想访问它只能通过该抽象类的子类。
C:abstract不能和哪些关键字共存?
a:final 冲突 因为最终方法不能被重写,而抽象的方法需要被具体的子类重写。
final abstract void show(); //错误: 非法的修饰符组合: abstract和private
b:private 冲突 因为私有方法不能被继承,所以就不能被重写,而抽象的方法需要被具体的子类重写。
private abstract void show(); //错误: 非法的修饰符组合: abstract和final
c:static 无意义 因为抽象方法是没有方法体的,而静态是可以直接通过类名访问的。访问一个没有方法体的方法,意义何在呢?
static abstract void show(); //错误: 非法的修饰符组合: abstract和static
-----------------------------------------------------------------------------
4:接口(掌握)
(1)回顾猫狗案例,它们仅仅提供一些基本功能。
部分的猫会钻火圈,狗会跳高等功能,不是动物本身就具备的,
是在后面的培养中训练出来的,所以,为了体现事物功能的扩展性,
Java中就提供了接口来定义这些额外功能,并不给出具体实现(说明是抽象方法),将来哪些猫狗需要被培训,只需要这部分猫狗把这些额外功能实现即可。
其实接口是最最抽象的抽象类。
---------------------------------------
(2)接口的特点:
A:接口用关键字interface修饰
interface 接口名 {}
B:类实现接口用implements修饰
class 类名 implements 接口名 {}
C:接口不能实例化
那么,接口如何实例化呢?
按照多态的方式来实例化。(即就要去做一个具体的子类,通过具体的子类去实例化)
由此可见,多态有几种方式:
1.具体类多态(几乎没有,但是讲解是通过具体类讲解的)
2.抽象类多态(常用)
3.接口多态(最常用)
D:接口的实现类(子类)
接口的实现类格式:接口名+Impl
a:接口的实现类是一个抽象类。但是意义不大,因为你是抽象类,最终还得需要具体子类。
//定义动物培训接口
interface AnimalTrain {
public abstract void jump();
}
//抽象类实现接口
abstract class Dog implements AnimalTrain {
}
b:接口的实现类是一个具体类,这个类必须重写接口中的所有抽象方法。(推荐方案)
//定义动物培训接口
interface AnimalTrain {
public abstract void jump();
}
//具体类实现接口
class Cat implements AnimalTrain {
public void jump() {
System.out.println("猫可以跳高了");
}
}
---------------------------------------
(3)接口的成员特点:
A:接口的成员变量特点:
只能是常量,并且是静态的。
因为接口的所有成员变量的默认修饰符都是:public static final
建议自己手动给出。
B:接口的构造方法特点:
接口没有构造方法 。
那么接口的实现类的无参构造方法默认访问的是谁的无参构造呢?
答:所有的类都默认继承一个类:Object类。
因为:类 Object 是类层次结构的根类。每个类都使用 Object 作为超类。
又因为:类 Object 只有无参构造方法,所以后来要求所有子类都默认调用的是父类的无参构造方法。
//接口名+Impl这种格式是接口的实现类格式
/*
class InterImpl implements Inter {
public InterImpl() {
super();
}
}
*/
//上面的写法等价于下面的写法
class InterImpl extends Object implements Inter {
public InterImpl() {
super();
}
}
C:接口的成员方法特点:
接口的成员方法只能是抽象的。
因为接口的所有成员方法的默认修饰符都是:public abstract
建议自己手动给出。
---------------------------------------
(4)类与类、类与接口、接口与接口的关系
A:类与类的关系
继承关系,只能单继承,不能多继承(只有一个父类),可以多层继承(可以有爷爷)。
class Son extends Father {} //正确
class Son extends Father, Mother {} //错误
B:类与接口的关系
1.实现关系,可以单实现,也可以多实现。(可以多扩展嘛)
2.还可以在继承一个类的同时,实现多个接口。(继承类 Object 嘛)
class Son implements Father, Mother {} //正确
class Son extends Object implements Father, Mother {} //正确
C:接口与接口的关系
继承关系,可以单继承,也可以多继承。
小结:Java中的类是单继承的,Java中的接口可以多继承。
---------------------------------------
(5)抽象类和接口的区别(自己补齐)?
A:成员区别
抽象类:
成员变量:可以有变量,也可以有常量
构造方法:有(用于子类访问父类数据的初始化)
成员方法:可以有抽象方法,也可以有非抽象方法
接口:
成员变量:只可以是常量
构造方法:无
成员方法:只可以是抽象方法
B:关系区别:
类与类:
继承关系,只能单继承和多层继承。
类与接口:
实现关系,可以单实现,也可以多实现。
接口与接口:
继承关系,可以单继承,也可以多继承。
C:设计理念不同
抽象类 被继承体现的是:“is a”的关系,抽象类中定义的是共性功能。
接口 被实现体现的是:“like a”的关系,接口中定义的是扩展功能。
---------------------------------------
(6)接口练习:
A:猫狗案例,加入跳高功能
共有六个类:(这里将接口理解为最最抽象的类)
跳高接口
动物类
猫类
狗类
有跳高功能的猫类
有跳高功能的狗类
测试类
示例代码如下:
/* 猫狗案例,加入跳高的额外功能 --------------------------------------- 分析:从具体到抽象 猫类: 姓名,年龄 吃饭,睡觉 狗类: 姓名,年龄 吃饭,睡觉 由于有共性功能,所以,我们抽取出一个父类, 抽象动物类: 姓名,年龄 吃饭(); 睡觉(){} 猫类:继承自抽象动物类 狗类:继承自抽象动物类 跳高的额外功能是一个新的扩展功能,所以我们要定义一个接口。 接口: 跳高 部分猫类:实现跳高 部分狗类:实现跳高 --------------------------------------- 实现;从抽象到具体 29 跳高接口 30 抽象动物类 31 抽象猫类 32 抽象狗类 33 具体的有跳高功能的猫类 34 具体的有跳高功能的狗类 35 测试类 使用: 使用具有跳高功能的具体类进行测试,因为具有跳高功能的具体类具有最多的功能。 */ //定义跳高接口 interface Jumpping { //跳高功能 public abstract void jump(); } //定义抽象动物类 abstract class Animal { //姓名 private String name; //年龄 private int age; public Animal() {} public Animal(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } //吃饭(); public abstract void eat(); //睡觉(){} public void sleep() { System.out.println("睡觉觉了"); } } //具体的猫类 class Cat extends Animal { public Cat() {} public Cat(String name,int age) { super(name, age); } public void eat() { System.out.println("猫吃鱼"); } } //具体的狗类 class Dog extends Animal { public Dog() {} public Dog(String name, int age) { super(name, age); } public void eat() { System.out.println("狗吃肉"); } } //有跳高功能的具体的猫类 class JumpCat extends Cat implements Jumpping { public JumpCat() {} public JumpCat(String name, int age) { super(name,age); } public void jump() { System.out.println("跳高猫"); } } //有跳高功能的具体的狗类 class JumpDog extends Dog implements Jumpping { public JumpDog() {} public JumpDog(String name, int age) { super(name,age); } public void jump() { System.out.println("跳高狗"); } } //测试类 class InterfaceTest { public static void main(String[] args) { //定义有跳高功能的具体的猫类并测试 //法一: JumpCat jc = new JumpCat(); jc.setName("哆啦A梦"); jc.setAge(3); System.out.println(jc.getName()+"---"+jc.getAge()); jc.eat(); jc.sleep(); jc.jump(); //法二: JumpCat jc2 = new JumpCat("加菲猫", 2); System.out.println(jc2.getName()+"---"+jc2.getAge()); jc2.eat(); jc2.sleep(); jc2.jump(); System.out.println("-----------------"); //定义有跳高功能的具体的狗类并测试 //法一: JumpDog jd = new JumpDog(); jd.setName("旺财"); jd.setAge(8); System.out.println(jd.getName()+"---"+jd.getAge()); jd.eat(); jd.sleep(); jd.jump(); //法二: jd = new JumpDog("旺财", 8); System.out.println(jd.getName()+"---"+jd.getAge()); jd.eat(); jd.sleep(); jd.jump(); } }
B:老师和学生案例,加入抽烟功能
共有六个类:(这里将接口理解为最最抽象的类)
抽烟接口
人类
学生类
老师类
有抽功能的学生类
有抽功能的老师类
测试类
示例代码同上,不在赘述!
=============================================================================
相关文章推荐
- java基础学习_面向对象(上)02_day07总结
- Java基础学习总结——面向对象
- java基础学习总结--面向对象
- Java基础学习总结(6)——面向对象
- java基础学习_基础语法(上)02_day03总结
- java基础学习总结——面向对象2
- java基础学习_常用类02_Scanner类和String类_day12总结
- Java基础学习总结(84)——Java面向对象六大原则和设计模式
- java基础学习总结——面向对象1
- java基础学习总结——面向对象
- java基础----面向对象5(关键字的总结学习)
- java基础学习总结——面向对象1
- Java基础学习总结(6)——面向对象
- java基础学习_面向对象(下)01_day08总结
- 黑马程序员[andriod]java基础学习日记四——面向对象的总结
- java基础学习总结——面向对象1
- Java基础学习总结(84)——Java面向对象六大原则和设计模式
- JavaSE学习总结第06天_Java语言基础2 & 面向对象1
- java基础学习总结——面向对象
- java基础学习_面向对象(上)01_day07总结