多态是否适用于Java中的类属性?

时间:2015-08-29 16:38:13

标签: java polymorphism

我知道当使用父类引用来引用像这样的子类对象时,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”,它取决于引用变量。

所以,我是对的吗?多态性不适用于类属性?

8 个答案:

答案 0 :(得分:8)

扩展类时,方法会被覆盖,但字段会被隐藏。动态分派适用于方法,但不适用于字段。为什么语言设计如此,天知道为什么。

答案 1 :(得分:6)

不,它没有。实例变量是特定类的属性,不会直接受到超类或子类和多态的影响。

你仍然可以通过在Dog中使用“super.name”和“this.name”来访问两个字段,但是如果你只使用“名字”,那么Dog中的那个将接管。如果你想要另一个你明确需要调用super。请注意,我正在谈论访问Dog类中的变量

答案 2 :(得分:4)

Dog.name 隐藏 Animal.name,这是一个非常糟糕的模式。任何好的IDE都会警告你,你正在这样做。

两个实例字段都存在,您可以从Dog this.namesuper.name访问这两个字段。

答案 3 :(得分:4)

动物的领域被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"
    }
}

答案 4 :(得分:2)

变量在Java中不是多态的;他们不会互相覆盖。

修改:为了进一步支持 Solver的答案,我记得我的OOP老师声称当您创建Child class对象时使用reference Parent class Child class Parent class中的变量Parent class中不存在仍然在运行时分配内存但无法作为Child class中没有可以访问{{1}}的变量的方法。

答案 5 :(得分:2)

基本上,当一个父类有一个孩子时,子类应该完全看起来像其父类,否则“如何称他们为父母和孩子?”对吗?无论如何,允许子类具有与其父类不同的行为。这很有意义和自然。

但是如果你想要覆盖子类的属性,你可以通过构造函数机制

来完成它

代码示例

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

答案 6 :(得分:1)

当您在print上调用animal方法时,JVM首先在print对象中搜索dog方法。如果print对象中没有dog方法,JVM将搜索Dog的超类。由于它在print类中找到Dog方法,因此它开始执行它。 Dog类中的name字段隐藏了从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);
    }
}

你所做的是糟糕的设计。

答案 7 :(得分:0)

在Java中,我们使用set和get方法来访问字段。在您的示例中,我们有一个Dog类扩展Animal类。

但是如果你把它声明为动物,如果直接调用字段Amimal dog1 = new Dog();你创建一个Dog实例,但是声明为Animal,那么当你调用dog1.name时,它会给你一个值动物