java的继承问题是笔试面试中常考的热点之一,请看下面几个例子,并加以比较:
在看例子之前,首先关于继承有以下几个原则:
(1)子类继承了其父类中不是私有的成员变量和成员方法,作为自己的成员变量和方法
(2)子类中定义的成员变量和父类中定义的成员变量相同时,则父类中的成员变量被隐藏
(3)子类中定义的成员方法,并且这个成员方法的名字,返回类型,及参数个数和类型与父类的某个成员方法完全相同,则父类的成员方法被覆盖。
Test1.java
package extend;
class A1{
int a = 1;
public int getA() {
return this.a;
}
}
class B1 extends A1 {
int a = 2;
}
public class Test1 {
public static void main(String[] args) {
B1 b =new B1();
System.out.println(b.getA());
}
}
此例中,B1继承了A1, 根据原则(2),父类中的int a 变量被隐藏,所以此时如果直接打印:b.a,得到的结果会是2。但是因为B1中没有同名的getA()方法,所以b.getA()中调用的getA()是继承自A1类的,A1类中的getA()调用的是它本身的a(A1.a),所以输出为: 1
Test2.java
package extend;
class A2{
int a = 1;
public int getA() {
return this.a;
}
}
class B2 extends A2 {
int a = 2;
public int getA() {
return this.a;
}
}
public class Test2 {
public static void main(String[] args) {
B2 b = new B2();
System.out.println(b.getA());
}
}
此例中与上个例子的不同之处在于,B2类中定义了同名的getA()方法覆盖了A2类中的同名方法,所以这里b.getA()调用的是B2类中的方法,又因为B2中的getA()方法引用的是B2类自身的变量a(B2.a),所以打印结果为: 2
Test3.java
package extend;
class A3 {
int a = 1;
public int getA() {
return this.a;
}
}
class B3 extends A3 {
public B3() {
a = 2;
}
}
public class Test3 {
public static void main(String[] args) {
B3 b = new B3();
System.out.println(b.getA());
}
}
此例中,子类(B3)既继承了父类(A3)的变量a,同时也继承了父类的getA()方法,所以B3()中的构造函数对a的赋值实际上是对继承自父类的变量a的赋值。由于没有覆盖,b.getA()调用的也是继承自父类A3的方法。输出结果很显然应该是 : 2
Test4.java
package extend;
class A4 {
int a = 1;
public int getA() {
return a;
}
}
class B4 extends A4 {
int a = 2;
public B4() {
a = 3;
}
}
public class Test4 {
public static void main(String[] args) {
B4 b = new B4();
System.out.println(b.getA());
}
}
此例中,子类B4中重新定义了同名的变量a,根据规则(2),A4中的变量a被隐藏,所以B4的构造函数中初始化的是B4类中的a,而由于没有重写方法覆盖getA(),所以b.getA()调用的仍然是A4类(父类)中的getA()方法,父类的getA()中返回的a自然是父类本身的变量a,而父类本身的变量a从初始化后一直没变,就是1,所以打印结果是: 1
顺便提一下:
1. 如果调用父类方法,则父类方法中引用的变量一定是父类中的变量(如Test1.java)
2.如果调用子类方法,那么:如果子类中没有重新定义父类中的某个变量(没有隐藏),而在子类方法中引用了,则引用的是父类的变量;如果在子类中重新定义了变量(实现了隐藏),则引用的是子类本身的变量