在Java中使用父类引用指向子类对象的作用是什么?
父类 引用 = new 子类()的写法? 你测试的代码能运行,是因为Java会自动完成向上转型——子类对象可以直接赋值给父类类型的变量/数组元素。但Pet p1 = new Dog("Fido")这种显式写法的价值,远不止“存入父类数组”这么简单,核心是为了利用多态和抽象编程的优势,具体来说有这些用处:
强制面向抽象,降低代码耦合度
如果用Dog p1 = new Dog("Fido"),后续代码可能会不小心调用Dog特有的方法(比如假设Dog有fetch()),这就把代码和Dog这个具体实现绑定死了。但如果用Pet p1,编译器只会允许你调用Pet类中定义的方法,后续要把Dog换成Cat,只需要修改new Cat("Mimi")这一行,其他使用p1的代码完全不用动,大幅降低了修改成本。统一处理多种子类对象
你现在只存了Dog,但如果数组里要同时放Dog、Cat、Bird这些Pet的子类,用父类引用能让你用一套逻辑处理所有对象。比如给Pet加一个抽象方法makeSound():public abstract class Pet { private String name; private String type; public Pet(String n, String t) { name = n; type = t; } public String toString() { return name + " is a " + type; } public abstract void makeSound(); } class Dog extends Pet { public Dog(String n) { super(n, "dog"); } @Override public void makeSound() { System.out.println("Woof!"); } } class Cat extends Pet { public Cat(String n) { super(n, "cat"); } @Override public void makeSound() { System.out.println("Meow!"); } }遍历数组时,直接调用
p.makeSound()就会自动执行对应子类的实现,不用写一堆if (p instanceof Dog)的判断,代码简洁且易扩展。提升方法的通用性
比如写一个领养宠物的方法:public void adopt(Pet pet) { System.out.println("Adopted " + pet); }这个方法能接收任何Pet子类对象(Dog、Cat都可以),如果参数写成
Dog dog,就只能处理Dog,灵活性差很多。返回值也是同理,一个方法可以返回任意Pet子类,调用方只用Pet类型接收,不用关心具体是哪个子类。增强代码封装性
假设你有一个工具类,内部创建了Dog对象,但对外返回Pet类型:public static Pet createPet(String type) { if (type.equals("dog")) { return new Dog("Fido"); } else if (type.equals("cat")) { return new Cat("Mimi"); } return null; }调用方拿到的是Pet引用,完全不知道内部创建的是Dog还是Cat,后续工具类新增其他Pet子类,调用方的代码完全不需要修改,封装性拉满。
至于你代码里Dog p1 = new Dog("Fido"); animals[0] = p1;能成功,是因为Java自动把Dog类型的p1向上转型为Pet类型存入数组。但显式写Pet p1 = new Dog("Fido")是在变量声明阶段就明确了“我只需要把这个对象当作Pet来使用”,代码意图更清晰,也能避免不小心依赖子类的特有功能。
内容的提问来源于stack exchange,提问作者Sarah

