5. 继承、多态、组合
5.1 继承
5.1.1 继承的语法
class SubClass extends SuperClass{
...
}
- 子类可以继承父类的所有成员,包括被private修饰的成员,子类只是无法访问、不能调用被private修饰的方法罢了。
- 子类不能继承父类的构造函数。
- 执行子类的构造方法之前,会先调用父类中没有参数的构造方法,其目的是为了要帮助继承自父类的成员做初始化操作。
- 子类继承的方法只能操作子类继承和隐藏的成员变量。
- 子类重写的方法也能直接操作被子类隐藏的成员变量。
- 但子类新增的方法不能直接操作被子类隐藏的成员变量。
5.1.2 成员变量的隐藏和方法的覆盖
- 隐藏(这里考虑实例
非常棒的参考:1.继承中方法和变量的覆盖和隐藏 2.同1
- 在Java中子类也可以隐藏由父类继承来的成员变量,只要子类中声明的成员变量和父类的成员变量同名,就可以将其隐藏。
- 子类对象可以调用从父类继承的方法操作隐藏的成员变量。
- 重写的方法既可以继承变量,也可以操作子类新声明的成员变量。如果子类想使用被覆盖的方法,必须使用关键字super。
- 实例中,变量被隐藏,方法被覆盖。
- 覆盖
1)覆盖是指在子类中定义名称、参数个数与类型均与父类中完全相同的方法,用以重写父类中同名方法的功能。方法头相同,方法体不同。
2)子类中不能覆盖父类中声明为final或static的方法。
3)在覆盖时访问权限只能放大或相同,不能缩小。
4)覆盖方法不能抛出新的异常。(?
5.1.3 super
如果想在子类中使用父类的非私有成员,可以使用super关键字。
super语句必须出现在子类构造方法非注释语句的第一行。
super.变量名;
super.方法名;
5.1.4 final
- final修饰类,表示该类不能被继承,即该类不能有String等子类。
- final修饰方法,表示该方法不能被重写。
- final修饰变量,该变量可以理解为常量,必须赋初值(可在声明时或在类的构造方法中赋值)。
5.2 多态
5.2.1 多态的理解
1.一个类有多个子类,并且这些类都重写了父类的某个方法。即多态存在在三个必要条件是:
继承;重写;父类引用指向子类对象:Parent p = new Child();
2.多态中,不能访问子类的特有成员,只能通过实例化子类对象来访问。
3.为此,介绍多态的两种转型:向上转型和向下转型。向上转型后子类不能调用自己的私有属性和私有方法,只能调用父类属性和重写的父类方法。如果向上转型后想要调用子类的私有属性和方法,可以强制向下转型。
临时问题:子类能调用自己的公有成员吗?
5.2.2 向上转型和向下转型
- 向上转型的理解:
1.由子到父,父类的引用指向子类对象,即 Animal a = new Cat();
2.当有子类对象赋值给一个父类引用时,便是向上转型,多态本身就是向上转型的过程。
3.格式:父类类型 变量名 = new 子类类型(); - 向下转型:
1.由子到父,父类的引用转为子类对象,即Cat c = (Cat)a; (强制类型转换)
2.一个已经向上转型的子类对象可以使用强制类型转换的格式,将父类引用转为子类引用,这个过程是向下转型。如果是直接创建父类对象,是无法向下转型的。
3.格式:子类类型 变量名 = (子类类型) 父类类型的变量;
例如:Cat c = (Cat)a; //变量a 实际上指向Cat对象
即新创建了一个Cat类型的对象c指向强制转换类型后的a
注:1.c和a的地址一样。2.关于对象存放在堆还是栈中,对象是存放在堆中 变量名存放在栈中,即如果new出来了一个对象就放在堆里,直接定义的局部变量(Cat c;)就放在栈里,此处对象c放在栈里。3.向下转型是有风险的,必须是继承关系才能转型成功,否则程序运行时就会抛出异常,为了防止这种情况,就要使用instanceof运算符。
“instanceof关键字的作用是判断左边对象是否是右边类(这里有很多人说是对象,所以注意这里是类,并不是对象)的实例(通俗易懂的说就是:子类对象,或者右边类本身的对象)返回的boolean类型,true和false。”
public class Test {
public static void main(String[] args) {
show(new Cat()); // 以 Cat 对象调用 show 方法,里面是匿名对象
show(new Dog()); // 以 Dog 对象调用 show 方法
Animal a = new Cat(); // 向上转型
a.eat(); // 调用的是 Cat 的 eat,向上转型后才能向下转型
Cat c = (Cat)a; // 向下转型
c.work(); // 调用的是 Cat 的 work
}
public static void show(Animal a) {
a.eat();
// 类型判断
if (a instanceof Cat) { // 猫做的事情
Cat c = (Cat)a;
c.work();
} else if (a instanceof Dog) { // 狗做的事情
Dog c = (Dog)a;
c.work();
}
}
}
abstract class Animal {
abstract void eat();
}
class Cat extends Animal {
public void eat() {
System.out.println("吃鱼");
}
public void work() {
System.out.println("抓老鼠");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("吃骨头");
}
public void work() {
System.out.println("看家");
}
}
执行以上程序,输出结果为:
吃鱼
抓老鼠
吃骨头
看家
吃鱼
抓老鼠
存疑:多态学习
5.3 组合
在一个新类中创建一个已有类的对象。