Java继承中对成员变量和方法的处理是不同的,看如下代码:
class Base {
public int count = 2;
public void display() {
System.out.println(this.count);
}
}
class Derived extends Base {
public int count = 20;
@Override
public void display() {
System.out.println(this.count);
}
}
public class Test {
public static void main(String[] args) {
Base b1 = new Base(); // (1)
System.out.println(b1.count);
b1.display();
Derived d1 = new Derived(); // (2)
System.out.println(d1.count);
d1.display();
Base b2 = new Derived(); // (3)
System.out.println(b2.count);
b2.display();
Base b3 = d1; // (4)
System.out.println(b3.count);
}
}
结果:
2
2
20
20
2
20
2
分析:
编译器处理方法和成员变量的区别:
看以下代码:
class Base { int count = 2; }
class Mid extends Base { int count = 20; }
class Sub extends Mid {int count = 200; }
public class Test {
public static void main(String[] args) {
Sub sub = new Sub();
Mid mid = sub;
Base base = sub;
System.out.println(sub.count);
System.out.println(mid.count);
System.out.println(base.count);
}
}
结果:
200
20
2
以上程序说明:sub、mid和base这3个变量指向的Java对象拥有3个count实例变量,也就是说,需要3块内存来存储它们
当Sub sub = new Sub();
这句执行完后,该对象在内存中的存储如下图所示:
内村中并不存在 Mid 和 Base 两个对象,只有一个 Sub 对象,只是这个 Sub 对象中不仅保存了在 Sub 类中定义的所有实例变量,还保存了它的所有父类所定义的全部实例变量,程序通过 Base 型变量访问该对象的count实例变量,将输出2,通过 Mid 型变量访问该对象的count实例变量,将输出20
看以下代码:
class Fruit {
String color = "unknow";
public Fruit getThis() {
return this;
}
public void info() {
System.out.println("Fruit's info()");
}
}
class Apple extends Fruit {
String color = "red";
@Override
public void info() {
System.out.println("Apple's info()");
}
public void accessSuperInfo() {
super.info();
}
public Fruit getSuper() {
return super.getThis();
}
}
public class Test {
public static void main(String[] args) {
Apple apple = new Apple();
Fruit fruit = apple.getSuper();
System.out.println("apple == fruit: " + (apple == fruit));
System.out.println("apple.color: " + apple.color);
System.out.println("fruit.color: " + fruit.color);
apple.info();
fruit.info();
apple.accessSuperInfo();
}
}
运行结果:
apple == fruit: true
apple.color: red
fruit.color: unknow
Apple's info()
Apple's info()
Fruit's info()
注意这个方法:
public Fruit getSuper() {
return super.getThis();
}
该方法尝试返回super关键字代表的内容,实际上,Java程序允许通过方法return this;返回调用该方法的Java对象,但不允许直接return super或者直接将super当成一个引用变量来使用,接下来会深入的分析这些语法规则
Apple apple = new Apple();
Fruit fruit = apple.getSuper();
apple == fruit 返回true,说明通过apple.getSuper()返回的是该Apple对象本身,只不过它的声明类型或者编译时类型是Fruit,所以通过 fruit 访问实例变量color,得到的是"unknow",而通过fruit调用info(),实际上就是调用apple对象的info()方法,调用accessSuperInfo();时使用super限定调用Fruit类的info()方法,所有该info()方法才真正表现出Fruit类的行为。
通过以上分析得出结论:super关键字本身并没有引用任何对象,它甚至不能被当成一个真正的引用变量,所以以下代码,编译就会报错:
super = new Fruit();
super = apple;
super = fruit;
总结:
类变量属于类本身,因此关于父类和子类的类变量的继承关系并不复杂,看如下代码:
class Base { public static int count = 20; }
class Sub extends Base {
public static int count = 200;
public void info() {
System.out.println("Sub's count = " + count);
System.out.println("Base's count = " + Base.count);
System.out.println("Base's count = " + super.count);
}
}
public class Test {
public static void main(String[] args) {
Sub sub = new Sub();
sub.info();
}
}
结果:
Sub's count = 200
Base's count = 20
Base's count = 20
总结: