前景提示:
1、之前一直以为子类继承父类的方法,本质是将父类的方法复制一份,然后粘贴到子类中,只不过在子类中看不见罢了。但是测试发现,方法只有一份,且始终在父类中。
2、方法能够重载,那么属性呢?
下面通过两个例子说明以上两个问题:
例一:
创建父类 Animal:
public class Animal {
public int id;
public void dis(){
System.out.println("id= " + id);
}
public Animal(){
id = 1;
System.out.println("父类无参构造方法执行");
}
}
创建子类Cat:
class Cat extends Animal{
public int id;
public Cat(){
id = 2;
System.out.println("子类无参构造方法执行");
}
}
创建测试类Test:
class Test{
public static void main(String[] args) {
Cat cat = new Cat();
cat.dis();
}
}
可以看到,父类与子类有一个同名属性id,先不必理会。在测试类中调用子类的dis()方法,该方法继承于父类,请问输出的id为多少?显然若按照我先前的思路,子类继承父类的方法,应该是将父类的方法复制一份,然后粘贴到了子类中,只不过在子类中看不到罢了,那么输出的id应该为子类的id ,但是控制台输出:
id= 1
即控制台输出父类的属性id,所以实际上方法只有一份,且这个方法始终位于父类中,并没有移动,创建子类对象,然后调用继承自父类的方法,实际上是进入父类中的方法进行调用。为验证这一结论,采用debug方法进入cat.dis()内部,发现直接进入Animal类的dis()方法 ,此时的id显然指向父类对象的id,所以输出id=1。
例二:修改例一的类进行实验
父类Animal:
public class Animal {
public String name;
public Animal(){
name = "父亲";
System.out.println("父类无参构造方法执行");
}
}
子类Cat:
class Cat extends Animal{
private String name;
public Cat(){
name = "儿子";
System.out.println("子类无参构造方法执行");
}
}
Cat cat = new Cat();
请问,能否调用cat的name属性?
答案是不能,这是很显然的,因为cat中的name属性被private修饰,即不能直接访问。但是容易让人产生疑惑:父类不是有一个public修饰的name属性吗?子类没有继承吗?
实际上,当子类创建了一个与父类同名的成员变量,会将父类同名的成员变量隐藏起来。注意不是完全覆盖,因此系统在创建子类对象时,仍然会为父类中定义的、被隐藏的变量分配内存空间。结合上面理解,当系统创建cat对象时,实际上会为cat对象分配两块内存,一块用于存储Cat类中定义的name实例变量,另一块则存储父类中定义的name实例变量。
那么,怎么调用被隐藏的父类成员变量呢?
可以采用super或者
Cat cat = new Cat();
Animal animal = (Animal)cat;//向上转型
System.out.prinln(animal.name);
这是因为,访问哪个实例变量(是父类的实例变量还是子类的实例变量)是由声明该变量的类型决定的,如上将cat对象向上转型为animal,此时声明animal该变量的类型为Animal,则访问animal的name属性,是访问Animal的实例变量,这也是多态的一大特色。