提问人:Toni Joe 提问时间:8/30/2015 最后编辑:Toni Joe 更新时间:8/30/2015 访问量:6089
多态性是否适用于 Java 中的类属性?
Does polymorphism apply on class attributes in Java?
问:
我知道 OOP 中多态性的常见用法发生在使用父类引用来引用子类对象时,如下所示:
Animal animal = new Animal();
Animal dog = new Dog();
我知道多态性适用于类方法,但它也适用于类属性吗?我试图用这个小例子来测试它:
public class Main{
public static void main(String args[]){
Animal animal = new Animal();
Animal dog1 = new Dog();
Dog dog2 = new Dog();
System.out.println("Animal object name: " + animal.name);
System.out.println("Dog1 object name: "+dog1.name);
System.out.println("Dog2 object name: " + dog2.name);
animal.print();
dog1.print();
dog2.print();
}
}
class Animal{
String name = "Animal";
public void print(){
System.out.println("I am an: "+name);
}
}
class Dog extends Animal{
String name = "Dog";
public void print(){
System.out.println("I am a: "+name);
}
}
这是输出:
Animal object name: Animal
Dog1 object name: Animal
Dog2 object name: Dog
I am an: Animal
I am a: Dog
I am a: Dog
正如你所看到的(我希望它是清楚的),多态性与print()方法一起工作得很好,但是对于类属性“name”,它取决于引用变量。
那么,我说得对吗?多态性不适用于类属性?
答:
不,它没有。实例变量是特定类的属性,不受超类或子类以及多态性的直接影响。
您仍然可以在 Dog 中使用“super.name”和“this.name”访问这两个字段,但如果您只使用“name”,则 Dog 中的字段将接管。如果你想要另一个,你明确需要调用 super。请注意,我说的是访问 Dog 类中的变量。
评论
Dog.name
是隐藏的,这样做是一个非常糟糕的模式。任何好的 IDE 都会警告你你正在这样做。Animal.name
这两个实例字段都存在,您可以从 as 和 .Dog
this.name
super.name
评论
变量在 Java 中不是多态的;它们不会相互覆盖。
编辑:为了进一步支持求解者的回答,我记得我的 OOP 老师声称,当你创建一个 的对象时,其中不存在的变量在运行时仍然分配内存,但无法访问,因为没有方法可以访问 的变量。Child class
reference
Parent class
Child class
Parent class
Parent class
Child class
评论
Child
Child
Parent
Child
Parent
Child
Parent
Animal 字段被 Dog 字段隐藏,您仍然可以通过引用 Animal 字段来访问它。
您期望的行为可以通过以下方式实现:
public class Main{
public static void main(String args[]){
Animal animal = new Animal();
Animal dog1 = new Dog();
Dog dog2 = new Dog();
System.out.println("Animal object name: " + animal.name);
System.out.println("Dog1 object name: "+dog1.name);
System.out.println("Dog2 object name: " + dog2.name);
animal.print();
dog1.print();
dog2.print();
}
}
class Animal {
String name = "Animal";
public void print(){
System.out.println("I am an: "+name);
}
}
class Dog extends Animal{
public Dog() {
this.name = "Dog"
}
}
评论
扩展类时,方法将被重写,但字段将被隐藏。动态调度适用于方法,但不适用于字段。为什么语言设计得如此,天知道为什么。
评论
在 Java 中,我们使用 set 和 get 方法来访问字段。在您的示例中,我们有一个扩展 Animal 类的 Dog 类。
但是,如果您将其声明为 Animal,则直接调用该字段将创建一个 Dog 实例,但声明为 Animal,因此当您调用时,它会为您提供 Animal 的值。Amimal dog1 = new Dog();
dog1.name
评论
当您调用 method on 时,JVM 会首先在对象中搜索方法。如果对象中没有方法,JVM 将搜索 的超类。由于它在类中找到方法,因此它开始执行它。类中的 name 字段隐藏从类继承的 name 字段。它就像:print
animal
print
dog
print
dog
Dog
print
Dog
Dog
Animal
public class Test {
static String name = "xyz";
public static void main(String[] args) {
{
String name = "abc";
System.out.println(name); // abc is printed
}
System.out.println(name); // xyz is printed
}
}
在块内部,有一个局部变量。所以全局变量是隐藏的。但是当你离开块时,局部变量就会生效。name
name
注意:
Dog
类应该是这样的:
class Dog extends Animal{
this.name = "Dog";
public void print(){
System.out.println("I am a: " + this.name);
}
}
你所做的是一个糟糕的设计。
基本上,当一个父类有一个子类时,子类应该完全看起来像它的父类,否则“你怎么能称他们为父类和子类?”对吧?无论如何,子类被允许具有与其父类不同的行为。这是很有道理和自然的。
但是,如果您确实想覆盖子类中的属性,则可以通过构造函数机制来完成
代码示例
class Animal{
String name;
public Animal(){
name = "Animal";
}
public Animal(String name){
this.name = name;
}
public void print(){
System.out.println("I am an: "+name);
}
}
class Dog extends Animal{
Dog(){
super("Dog");
}
public void print(){
System.out.println("I am a: "+name);
}
}
您将看到类中的属性名称是通过构造函数传递的,在这里我们可以通过关键字调用父类的构造函数。"Dog"
Dog
super
结果:
Animal object name: Animal
Dog1 object name: Dog
Dog2 object name: Dog
I am an: Animal
I am a: Dog
I am a: Dog
评论
static