我知道当使用父类引用来引用像这样的子类对象时,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”,它取决于引用变量。
所以,我是对的吗?多态性不适用于类属性?
答案 0 :(得分:8)
扩展类时,方法会被覆盖,但字段会被隐藏。动态分派适用于方法,但不适用于字段。为什么语言设计如此,天知道为什么。
答案 1 :(得分:6)
不,它没有。实例变量是特定类的属性,不会直接受到超类或子类和多态的影响。
你仍然可以通过在Dog中使用“super.name”和“this.name”来访问两个字段,但是如果你只使用“名字”,那么Dog中的那个将接管。如果你想要另一个你明确需要调用super。请注意,我正在谈论访问Dog类中的变量 。
答案 2 :(得分:4)
Dog.name
隐藏 Animal.name
,这是一个非常糟糕的模式。任何好的IDE都会警告你,你正在这样做。
两个实例字段都存在,您可以从Dog
this.name
和super.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
时,它会给你一个值动物