第五章 子类与继承
5.1 子类与父类
所有类的祖先类都是
Object
类
用extends
关键字来定义一个类的子类,如:
class A {
...
}
class B extends A {
...
}
5.2 子类的继承性
-
同一包当中的继承性:继承父类当中不是private的方法和变量
-
不同包的继承性:只能继承protected类和public类,不继承友好类和private类
5.3 子类和对象
5.3.1 子类对象的特点
子类在继承时,也同样为private的方法和变量分配了空间,虽然分配了内存空间但是其并非子类对象的变量,或者说,获取了相应的值和函数,但是并没有直接访问和调用他们的权力。当然,子类可以通过其他的方法来操作这些没有访问权限的变量,例如
class A {
private int x;
public int getX() {
return x;
}
}
class B extends A {
...
}
显然B的对象没有权利直接访问x的值
B b = new B();
int i = b.x // 非法
int j = b.getX() // 合法,因为getX方法类型为public,能够被B类继承
5.3.2 关于instanceod运算符
instanceod运算符是Java独有的双目运算符
该左面的操作元是对象,右面的操作元是类,当左边的操作元是右侧的类或者其子类创建的对象时,instanceod运算符的结果为true, 否则是false,参考5.3.1的代码:
boolean x;
x = b boolean A; // true
5.4 成员变量的方法与重写
5.4.1 成员变量的隐藏
- 对于子类从父类继承的成员变量,只要子类声明的成员变量和父类继承的成员变量同名,则子类就会将继承的成员变量隐藏
- 子类中操作这个同名变量时,子类中的方法操作的是子类的变量,继承自父类的方法操作的是隐藏的父类的变量
class A {
int x = 10;
int getX() {
return x;
}
}
class B extends A {
int x; // 子类又声明了一个x,父类的x被隐藏
setX(int i) {
x = i;
}
}
现在进行这些操作
B b = new B();
b.setX(100); // 此时对象b中B新建立的x值是100
int a = b.getX(); // a的值还是10
5.4.2 方法重写
- 重写的语法规则:如果子类可以继承父类的某一个方法,那么就有权利重写它。重写的方法与父类的方法一致,且名字、参数个数、参数类型与父类完全相同
class A {
int x = 10, sum;
int getSum(int a) {
sum = x + a;
return sum;
}
}
class B extends A {
int sum;
int getSum(int a) { // 重写了方法int getSum(int a)
sum = x + x + a;
return sum;
}
}
- 重写的目的:隐藏继承的方法
- 特别注意:重载和重写的区别,在习题中经常出现需要分辨重载和重写的情况
- 重写父类方法时,不允许降低方法的访问权限,访问权限由高到低为:public > protected > 友好 > private
class A {
protected int getSum(int a, int b) {
return a + b;
}
}
class B extends A {
int getSum(int a, int b) { // 非法,降低了访问权限
return (a + b)*2;
}
}
class C extends A {
public int getSum(int a, int b) { // 合法
return a + a + b;
}
}
5.5 Super
关键字
5.5.1 用super操作被隐藏的成员变量和方法
使用super关键字可以访问和调用被子类隐藏的成员变量和方法
super关键字实例如下:
class A {
int n = 100;
}
class B extends A {
int n = 10;
int g() {
return n;
}
int f() {
return super.n;
}
}
主程序中执行:
int i, j;
B b = new B();
i = b.g() // i = 10
j = b.f() // b = 100
5.5.2 使用super调用父类构造方法
- 需要复习“构造方法”部分内容
5.6 final
关键字
final关键字可以修饰类,成员变量和方法当中的局部变量
- final类:final类不能被继承,即不能有子类
- final方法:如果父类当中存在final方法,那么这个方法不允许子类重写
- 常量:用final声明的变量不允许任何修改,所以在声明常量时必须给出ta的值,如:
final double PI = 3.14;
5.7 对象的上转型对象
class A {
private int a = 100;
static void f() {
System.out.println("Well done!");
}
void outPut() {
System.out.println(a);
}
void print() {
System.out.println("Hello Word!");
}
}
class B extends A {
static void f() {
System.out.println("Go for it!");
}
void print() {
System.out.println("This is a Java program");
}
void compute(int a, int b) {
System.out.println("两数相加的结果是:"+ a + b);
}
}
显然A是B的父类
下面用子类B创建一个对象
A a; // 将对象的引用放到父类当中
a = new B(); //用子类创建了一个对象
或者写作
Animal a;
Tiger b = new Tiger();
a = b;
此时称 a 是对象 b 的上转型对象
上转型对象会失去子类对象的一些特点
1.上转型对象不能操作子类新增的变量和方法
a.compute(10, 20); // 非法,a作为上转型对象不能操作子类新增的compute方法
2.上转型对象能访问子类继承和隐藏的变量、方法
a.outPut(); // 合法,a作为上转型对像可以调用子类继承的方法
3.上转型对象能操作子类继承或者重写的方法,但是如果子类重写了父类的静态方法,那么它只能调用父类的静态方法而不能调用子类重写的静态方法
a.print(); // 合法,输出This is a Java program"
4.如果子类重写父类的静态方法,那么子类的上转型对象不能调用子类重写的静态方法,只能调用父类的静态方法
a.f(); // 合法,输出"Well done",因为上转型对象只能调用父类的静态方法
5.8 继承与多态
一个类的各个子类如果都重写了父类中的同一个方法,而且这些子类创建的对象都定义为子类的上转型对象,那么各个子类就会产生各自的功能行为,我们称次现象为“多态”
5.9 abstract类和abstract方法
抽象方法和抽象类用abstract关键字修饰
-
对于abstract方法,只允许声明,不允许实现(没有方法体),不允许final和abstract同时修饰同一个方法或类,也不允许static修饰abstract方法
-
对于abstract类
- abstract类当中可以有abstract方法,也可以有非abstract方法
abstract Class A { abstract void a(); // abstract方法 void b(); // 非abstract方法 }
- abstract类不能使用new创建该类的对象实体;如果某个非抽象类是抽象类的子类,那么如果它继承的方法中有抽象方法,则必须将其重写,这样才能创建该子类的实体
// 代码接1 class B extends A { void a() { // 必须重写abstract方法 ... } }