Java 为什么通过方法返回子类对象调用超类变量?
我知道变量没有多态性。如果我们执行新的Subclass().x,那么在运行时将打印值20。 但是这里是Java 为什么通过方法返回子类对象调用超类变量?,java,Java,我知道变量没有多态性。如果我们执行新的Subclass().x,那么在运行时将打印值20。 但是这里是 Parent p = new Child(); p.getObject(); 子类的getObject()将被调用,因为子类的getObject将覆盖超类的getObject()。因此子类方法getObject()返回新的Child(),所以打印的值应该是Child.x ie 20的值。但是输出是10。为什么x的值是超类的值???我知道有一些帖子与此相关,但并不是所有地方都解释了这一点
Parent p = new Child();
p.getObject();
子类的getObject()将被调用,因为子类的getObject将覆盖超类的getObject()。因此子类方法getObject()返回新的Child(),所以打印的值应该是Child.x ie 20的值。但是输出是10。为什么x的值是超类的值???我知道有一些帖子与此相关,但并不是所有地方都解释了这一点。请帮忙
class MainClass {
public static void main(String[] args) {
Parent p = new Child();
System.out.println(p.getObject().x);
}
}
class Parent {
int x = 10;
public Parent getObject() {
return new Parent();
}
}
class Child extends Parent {
int x = 20;
public Child getObject() {
return new Child();
}
}
您正在类
Parent
中访问变量x
,因为p.getObject()
的声明类型是Parent
顺便说一句:访问对象内部的变量直接违反了OOP最基本的原则:信息隐藏/封装!您应该仅对用作纯数据容器且自身没有业务逻辑的数据传输对象/值对象执行此操作。即使在那里,您也应该使用getter/setter方法,而不是直接访问变量…您正在访问类
Parent
中的变量x
,因为p.getObject()
的声明类型是Parent
顺便说一句:访问对象内部的变量直接违反了OOP最基本的原则:信息隐藏/封装!您应该仅对用作纯数据容器且自身没有业务逻辑的数据传输对象/值对象执行此操作。即使在那里,您也应该使用getter/setter方法而不是直接变量访问…这都是关于Java中的内存分配的 有
Parent p=new Child()
意味着您正在堆上创建一个属于类Child的对象和一个名为p的对该对象的引用,但此引用旨在与类Parent的对象一起操作。
因此,您正在分配一个类型为Child的对象,但引用正在使用Parent操作
这意味着,引用将无法看到子对象的x属性。它将只看到父属性
检查一下,它也是关于Java中内存分配的 有
Parent p=new Child()
意味着您正在堆上创建一个属于类Child的对象和一个名为p的对该对象的引用,但此引用旨在与类Parent的对象一起操作。
因此,您正在分配一个类型为Child的对象,但引用正在使用Parent操作
这意味着,引用将无法看到子对象的x属性。它将只看到父属性
查看,以及您所做的被称为阴影。若您声明的变量名称已在可访问范围内定义,那个么该变量将隐藏(隐藏)已定义的变量。若要使用外部作用域中的变量,必须写入该变量的绝对路径或使用该变量唯一的访问器
public class A {
int a;
public A(int a) {
System.out.println(a); // arg "a" has shadowed class field
System.out.println(this.a);
// that's why we are using this assignment:
this.a = a;
}
}
你的例子也是如此child.x
已隐藏了parent.x
字段。如果对象引用为子类
类型i。e<代码>子项c=新子项(),则默认情况下将使用最近的可访问变量x
(Child.x
)。如果您的对象引用属于父对象
类型i。e<代码>父级p=新父级(),然后再次使用最近的可访问的x
(Parent.x
)。这同样适用于Parent p=new Child()代码>由于p
是新的子项
但升级为Parent
类型,因此p.x
将显示Parent.x
值
您只需记住,多态性不适用于类字段。除非字段值包装在某个getter中,否则不能重写它
因此,如果您需要覆盖显示的值,则必须将该值包装在某个getter中,该getter将被子类
覆盖:
public class Test {
public static void main(String[] args) {
Parent p = new Child();
System.out.println(p.getObject().getValue()); // 20
System.out.println(p.getValue()); // 20
}
static class Parent {
int x = 10;
public int getValue() {return x;}
public Parent getObject() {return new Parent();}
}
static class Child extends Parent {
int x = 20;
@Override
public int getValue() {return x;} // return Child.x
@Override
public Child getObject() {return new Child();}
}
}
你所做的被称为“阴影”。若您声明的变量名称已在可访问范围内定义,那个么该变量将隐藏(隐藏)已定义的变量。若要使用外部作用域中的变量,必须写入该变量的绝对路径或使用该变量唯一的访问器
public class A {
int a;
public A(int a) {
System.out.println(a); // arg "a" has shadowed class field
System.out.println(this.a);
// that's why we are using this assignment:
this.a = a;
}
}
你的例子也是如此child.x
已隐藏了parent.x
字段。如果对象引用为子类
类型i。e<代码>子项c=新子项()
,则默认情况下将使用最近的可访问变量x
(Child.x
)。如果您的对象引用属于父对象
类型i。e<代码>父级p=新父级(),然后再次使用最近的可访问的x
(Parent.x
)。这同样适用于Parent p=new Child()代码>由于p
是新的子项
但升级为Parent
类型,因此p.x
将显示Parent.x
值
您只需记住,多态性不适用于类字段。除非字段值包装在某个getter中,否则不能重写它
因此,如果您需要覆盖显示的值,则必须将该值包装在某个getter中,该getter将被子类
覆盖:
public class Test {
public static void main(String[] args) {
Parent p = new Child();
System.out.println(p.getObject().getValue()); // 20
System.out.println(p.getValue()); // 20
}
static class Parent {
int x = 10;
public int getValue() {return x;}
public Parent getObject() {return new Parent();}
}
static class Child extends Parent {
int x = 20;
@Override
public int getValue() {return x;} // return Child.x
@Override
public Child getObject() {return new Child();}
}
}
在java中,不需要简单地重写变量!还有。。。。您正在执行返回新父对象()的操作;如果我写new Child().x,那么打印的值将是20,而不是p.getObject().x。但是p.getObject()输出是new Child(),然后转换为new Child().x,但输出仍然是10。为什么父类中的getObject()会被子类getObject()覆盖,对吗?java中的变量不是简单的覆盖!还有。。。。您正在执行返回新父对象()的操作;如果我写新的Child().x,那么打印的值将是20,而不是p.getObject().x