(1)引用替换规则:父类声明可引用所有具体子类对象就意味着父类声明所引用的对象可以被替换。子类声明不能引用平行级别的其他类对象,也不能引用父类对象。
(2)父类声明和子类声明都引用同一个子类对象时的区别:父类声明是从父类的角度去引用对象,而子类声明是从子类角度引用对象。父类声明所引用的子类对象可以经过显式的转换(造型cast)赋值给子类声明,但子类声明所引用的子类对象赋值给父类声明则不需要显式的转化。
例题:
public class ParentDog {
public String dogName;
public ParentDog(String dogName) {
this.dogName = dogName;
}
}
class SonDog extends ParentDog {
public String dogName;
public SonDog(String dogName, String parentDogName) {
super(parentDogName);
this.dogName = dogName;
}
}
public class RunDog {
public static void main(String[] args) {
ParentDog pDog; //(1)
SonDog sDogA, sDogB; //(2)
pDog = new ParentDog("Jack");
System.out.println("pDog = new ParentDog(\"Jack\"):");
System.out.println("pDog的名字是:"+pDog.dogName+"\n");
sDogA = new SonDog("sonA","JackA"); //(3)
sDogB = new SonDog("sonB","JackB"); //(4)
pDog = sDogA; //(5)
System.out.println("pDog = sDogA:");
System.out.println("pDog的名字是:"+pDog.dogName);
System.out.println("sDogA的名字是:"+sDogA.dogName);
System.out.println("sDogB的名字是:"+sDogB.dogName+"\n");
pDog = sDogB; //(6)
System.out.println("pDog = sDogB:");
System.out.println("pDog的名字是:"+pDog.dogName);
System.out.println("sDogA的名字是:"+sDogA.dogName);
System.out.println("sDogB的名字是:"+sDogB.dogName);
}
}
运行结果:
程序说明:
(1)sonDog继承parentDog,它们都有属性dogName,因而sonDog从parentDog继承的dogName发生了数据隐藏。RunDog的执行情况如图(图中阴影部分表示数据隐藏)。
(2)在发生数据成员隐藏的情况下,虽然父类声明和子类声明引用了同一个子类对象,但是父类引用访问的是隐藏的成员。
(3)如果子类没有定义dogName,则父类引用和子类引用访问的是同一个 dogName;(如下)
public class ParentDog {
public String dogName;
public ParentDog(String dogName) {
this.dogName = dogName;
}
}
class SonDog extends ParentDog {
public SonDog(String parentDogName) {
super(parentDogName);
}
}
public class RunDog {
public static void main(String[] args) {
ParentDog pDog;
SonDog sDogA, sDogB;
pDog = new ParentDog("Jack");
System.out.println("pDog = new ParentDog(\"Jack\"):");
System.out.println("pDog的名字是:"+pDog.dogName+"\n");
sDogA = new SonDog("JackA");
sDogB = new SonDog("JackB");
pDog = sDogA;
System.out.println("pDog = sDogA:");
System.out.println("pDog的名字是:"+pDog.dogName);
System.out.println("sDogA的名字是:"+sDogA.dogName);
System.out.println("sDogB的名字是:"+sDogB.dogName+"\n");
pDog = sDogB;
System.out.println("pDog = sDogB:");
System.out.println("pDog的名字是:"+pDog.dogName);
System.out.println("sDogA的名字是:"+sDogA.dogName);
System.out.println("sDogB的名字是:"+sDogB.dogName);
}
}
运行结果:
(4)如果父类没有定义dogName,而子类定义了dogName,则子类引用可以访问dogName,而父类引用访问dogName,则编译不会通过。(如下)
public class ParentDog {
public ParentDog() {}
}
class SonDog extends ParentDog {
public String dogName;
public SonDog(String dogName) {
this.dogName = dogName;
}
}
public class RunDog {
public static void main(String[] args) {
ParentDog pDog;
SonDog sDogA, sDogB;
pDog = new ParentDog();
System.out.println("pDog = new ParentDog():"+"\n");
// System.out.println("pDog的名字是:"+pDog.dogName+"\n");编译报错
sDogA = new SonDog("sonA");
sDogB = new SonDog("sonB");
pDog = sDogA;
System.out.println("pDog = sDogA:");
// System.out.println("pDog的名字是:"+pDog.dogName);编译报错
System.out.println("sDogA的名字是:"+sDogA.dogName);
System.out.println("sDogB的名字是:"+sDogB.dogName+"\n");
pDog = sDogB;
System.out.println("pDog = sDogB:");
// System.out.println("pDog的名字是:"+pDog.dogName);编译报错
System.out.println("sDogA的名字是:"+sDogA.dogName);
System.out.println("sDogB的名字是:"+sDogB.dogName);
}
}
运行结果:
(5)如果子类覆盖了父类的同名方法,则父类声明引用子类对象时调用的不是父类的方法体内容,而是子类方法体中的内容,因为Java方法没有隐藏的概念。(如下)
public class ParentDog {
public String dogName;
public ParentDog(String dogName) {
this.dogName = dogName;
}
public void Wow() {
System.out.println(dogName + " wow!");
}
}
class SonDog extends ParentDog {
public String dogName;
public SonDog(String dogName, String parentDogName) {
super(parentDogName);
this.dogName = dogName;
}
public void Wow() {
System.out.println(dogName + " wow!");
}
}
public class RunDog {
public static void main(String[] args) {
ParentDog pDog;
SonDog sDogA, sDogB;
pDog = new ParentDog("Jack");
System.out.println("pDog = new ParentDog(\"Jack\"):");
System.out.println("pDog的名字是:"+pDog.dogName);
System.out.print("pDog.Wow(): ");
pDog.Wow();
System.out.println();
sDogA = new SonDog("sonA","JackA");
sDogB = new SonDog("sonB","JackB");
pDog = sDogA;
System.out.println("pDog = sDogA:");
System.out.println("pDog的名字是:"+pDog.dogName);
System.out.print("pDog.Wow(): ");
pDog.Wow();
System.out.println("sDogA的名字是:"+sDogA.dogName);
System.out.print("sDogA.Wow(): ");
sDogA.Wow();
System.out.println("sDogB的名字是:"+sDogB.dogName);
System.out.print("sDogB.Wow(): ");
sDogB.Wow();
System.out.println();
pDog = sDogB;
System.out.println("pDog = sDogB:");
System.out.println("pDog的名字是:"+pDog.dogName);
System.out.print("pDog.Wow(): ");
pDog.Wow();
System.out.println("sDogA的名字是:"+sDogA.dogName);
System.out.print("sDogA.Wow(): ");
sDogA.Wow();
System.out.println("sDogB的名字是:"+sDogB.dogName);
System.out.print("sDogB.Wow(): ");
sDogB.Wow();
}
}