Java
中的继承是面向对象程序设计的一大特征,子类继承了父类的所有方法和成员变量,如果不对方法进行重写或对成员变量进行重新赋值,那么子类可以直接调用父类中的方法或变量。同时,在实例化父类的时候,可以使用子类的构造器。
但是,在这种情况下,调用这个父类对象中的方法和变量时,到底是使用父类的呢还是子类的呢?我们首先来创建两个类:
public class Animal{
static String name = "animal";
int num = 1; //成员变量
public static void sleep() {
System.out.println("animal sleep");
}
public void run() {
System.out.println("animal run");
}
}
public class Cat extends Animal{
static String name = "cat";
int num = 2;
public static void sleep() {
System.out.println("cat sleep");
}
public void run() {
System.out.println("cat run");
}
}
可以看到,Animal类中声明了静态成员变量name、成员变量num、方法run()和静态方法sleep(),同时子类Cat中也重写了这两个两个方法。下面,我们用Cat的构造方法来实例化一个Animal,再实例化一个Cat对象。
public static void main(String args[]) {
Cat cat = new Cat();
Animal animal = new Cat();
System.out.println(cat.num);
System.out.println(animal.num);
System.out.println(cat.name);
System.out.println(animal.name);
cat.run();
animal.run();
cat.sleep();
animal.sleep();
}
运行后可以看到:
2
1
cat
animal
cat run
cat run
cat sleep
animal sleep
可以看到,在输出两个对象中的各个变量时,Animal对象并没有因为构造函数使用了其子类而输出子类中的成员变量值,但是,在调用成员变量的时候就不一样了,在调用run()方法时,Animal输出和Cat一样的结果,而在调用静态方法sleep()的时候,两个对象又分别输出了其各自的结果。
- 总结,在调用成员变量以及静态方法时,“编译看左边,运行看左边”即程序编译时创建了一个Animal类型的对象,并且使用new Cat()对于这个Animal对象赋值,但最终得到的还是一个Animal类的对象,只需要看“=”左边的Animal animal即可。
- 但是要调用非静态方法时,由于Animal类的对象是用Cat()来实例化的,这个非静态方法在运行时会被重写,从而输出子类中方法重写后的结果。这就是“编译看左边,运行看右边”。