一、子类和父类的关系
1、构造方法
子类在新建对象时,首先调用父类的构造方法,然后调用自己的构造方法。
2、成员变量
(1)子类可以继承父类public和protected修饰的成员变量和成员方法。
(2)子类覆盖父类的成员变量
3、成员方法
子类覆盖父类的同名同参数列表方法(重写),可以利用super调用父类被覆盖方法。
4、类型转换
(1)子类转父类(向上转换)
例如:B是继承A的子类,对于如下对象:
class A {
}
class B extends A {
}
A A1 = new B();
那么A1只能调用父类和子类同时拥有的变量和成员方法。存在覆盖的情况时,成员方法调用子类,成员变量调用父类。
(2)父类转子类
会报错。
(3)不同子类之间转换
只保留共有的成员方法,重复的以赋值对象为准。成员变量为父类。
5、隔代继承
当直接父类和祖父类存在同名成员变量和成员方法时,采用就近原则,调用直接父类的。
二、重写
1、含义
当一个子类继承一个父类的时候,可以重写覆盖原来父类里面的方法,这个方法要求和父类方法的名称相同,参数列表相同。
2、需要满足的条件
(1)父类中的方法在子类中必须可见。对于父类中的private 方法,子类虽能继承,但无法访问和覆盖;对于父类中final的方法,子类继承但不能重写。
(2)子类和父类的方法必须是实例方法,如果父类是 static 方法而子类是实例方法,或者相反都会报错。如果父类和子类都是 static 方法,那么子类隐藏父类的方法,而不是重写父类方法。
例如:child类继承parent类,同时两者都有一个static方法printA。
class parent {
public static void printA() {
System.out.println("父类静态");
}
public void printB() {
System.out.println("父类普通");
}
}
class child extends parent {
public static void printA() {
System.out.println("子类静态");
}
public void printB() {
System.out.println("子类普通");
}
}
public static void main(String[] args) {
child c1 = new child();
c1.printA();
c1.printB();
}
则在执行main函数时,最后结果为
运行结果
(3)子类和父类的方法名、参数列表必须相同(定义),并且子类的返回值与父类相同或者是父类返回类型的子类型(jdk1.5 之后,否则会报错)。如果方法名称相同而参数列表不同,那么只是方法的重载,而非重写。
原因:
假设 B 是 A 的子类,初始化 a 为 B 类型,并调用 B 类重写过的方法 func():
A a = new B();
C aa = a.func();
A类中func返回值为C类型,若B类中func的返回值不是C类或其子类,则会出现错误。
(4)子类方法的访问权限不能小于父类方法的访问权限。访问权限由高到低:public、protected、包访问权限、private。
原因:
假设一个父类 A 拥有的方法 public void func() {} 可以被其他任意对象调用。这个方法被子类 B 覆写后为 void func() {} 即默认的访问权限只能被本包极其子类所访问。
假设其他包中的对象 C 调用方法:
void get(A a) {
a.func();
}
假设此时传入的对象为 B 类对象 b,此时 b 将转型为 a 但是 b 中的 func() 调用权限已经被缩小了,这将会造成错误。
(5)子类方法不能比父类方法抛出更多的编译时异常(不是运行时异常),即子类方法抛出的编译时异常或者和父类相同或者是父类异常的子类。
原因:
子类在覆盖父类方法的时候,父类的引用可以调用该方法。如果父类的引用调用子类的方法,那么这个多抛出来的异常,就可能处于一种无法被处理的状态。
总的来说,子类的规约应当强于父类。