如何从子类而非父类获取数据字段?

4

我有一个名为TestSuper的超类

public class TestSuper {
  int a = 0;
}

我有两个子类,分别叫做TestSubTestSub2,它们继承自TestSuper

public class TestSub extends TestSuper{
   int a=1;
}

public class TestSub2 extends TestSuper{
   int a=2;
}

在我的主类中,我创建了一个方法,该方法接受一个类型为TestSuper的参数,并返回它的值。在主程序中,我将其显示在控制台上。
public class Main {
public static void main(String[] args){

    System.out.println(test(new TestSub())+" "+test(new TestSub2()));
}
public static int test(TestSuper b){
    return b.a;
}
}

但是输出的结果是"0 0"而不是"1 2",我该怎么办?

2
你只能在子类中重写方法,而不能重写字段。 - Joe C
在你的子类中添加一个构造函数 TestSub(){ a = 1;} - Maraboc
4个回答

3

您需要进行引用转换,以确定您需要哪一个。

public static int test(TestSuper b){
    return b instanceof TestSub ? ((TestSub) b).a :
           b instanceof TestSub2 ? ((TestSub2) b).a :
           b.a;
}

如果这看起来过于复杂,那么确实如此。您应该使用多态性。
public class TestSuper {
    int a = 0;
    public int getA() { return a; }
}

public class TestSub extends TestSuper {
    int a = 1;
    public int getA() { return a; }
}

public class TestSub2 extends TestSuper {
    int a = 2;
    public int getA() { return a; }
}

public static int test(TestSuper b) {
    return b.getA();
}

如果在子类中重新定义字段并将子类的实例强制转换为超类,则返回的值是超类的值,但是如果通过方法或getter要求该值,则返回的值是子类的值!!之前不知道这点,现在想知道为什么? - Charif DZ
@Charif 非静态方法遵循继承,字段不会。 - Peter Lawrey
1
现在我想象一下,一个子类实例包含两个具有相同名称但不同值的字段。这就是正在发生的事情吗? - Charif DZ
我读了你关于内存泄漏的博客,这个例子中是否存在内存泄漏?因为a = 0永远不会被使用,但它一直存在。 - Charif DZ
@Charif 是的。字段名称概念上包括声明类。 - Peter Lawrey
@Charif 这不是通常所说的内存泄漏,但你可以说它是。 - Peter Lawrey

0

0

你可以研究一下这个理论,然后做唯一合理的事情——忘记写这种代码。

在良好的面向对象编程中,你应该将你的字段视为“秘密”内部实现的一部分。你不应该在超类上下文中使用子类的字段。这是绝对不允许的。

甚至在超类中将一个字段设置为受保护的,并在子类中使用它也要非常谨慎。


0
当您像这样调用测试方法时:
test(new TestSub())+" "+test(new TestSub2())

您正在使用向上转型。向上转型将一个对象的接口和实现分离。但是,为了将接口和实现分开,并在多态性中实现真正的实现,您必须使用多态结构。实例变量不是多态的。因此,您实际上调用的是TestSuper类中的变量。

只有实例方法是多态的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接