天真的继承问题 - Java

4

大家好,

我感到有些尴尬,因为我要问一个很幼稚的问题。但是我不明白一件事情,我的继承结构如下所示:

enter image description here

B 继承自 A,我编写的代码如下:

Class A

public class A{
    private int pos = 0;
    public A(){
        this.pos = 12;
    }
    public int getPos(){
        return this.pos;
    }
}

类 B

public class B extends A{
    int spec = 15;
    public B(){
        super();
    }
    public int getSpec(){
        return this.spec;
    }
}

我还有一个测试类需要执行,这将引出我的问题。

测试类

import java.util.*;
public class Test{
    public static void main(String[] args){
        B a = new B();
        ArrayList<A> c = new ArrayList<A>();
        c.add(a);
        System.out.println(c.get(0).getPos());
        System.out.println(c.get(0).getSpec());
    }
}

问题:现在我正在创建B的实例,这意味着我可以访问我的父类的方法getPos()和B自己的方法getSpec()。但是,如果我使用类型为A(...B也是类型A,因为它扩展了A...)创建ArrayList并添加我的B实例,则它失去了访问自己方法的能力。我做错了什么?ArrayList实现是否在内部将我的B转换为A?
注意:我的继承基本理解是父类不能访问子类的方法,除非它们是受保护的。但是子类可以访问其父类的方法。
3个回答

4

这里没有涉及到类型转换。你所做的事情与这个例子没有什么区别:

A bAsA = new B():

虽然 bAsA 所引用的对象确实是 B 对象,但它被 A 变量持有,因此只有 A 方法可用(除非您将其显式转换为 B 变量)。

由于您的 ArrayList 是一个 A 类型的 ArrayList,因此 ArrayList 中的每个项都被视为一个 A 变量,并且只有 A 方法可用。


4

谢谢,马特,现在这个有意义了:)。顺便问一下,如果我想要一个子项的集合存储在一个ArrayList中,可以这么做吗?比如 ArrayList<Obejct>...; 然后每次强制转换吗?还是有什么其他方法? - TeaCupApp
2
@Skeet:过度的类型转换会让程序变得臭气熏天,并暗示着我们应该仔细审视程序设计,因为很有可能它已经损坏了,可以通过更加面向对象的方式进行改进。 - Hovercraft Full Of Eels
2
@Skeet 我不建议使用强制类型转换。如果你想在 AB 上调用相同的方法,那就不要担心类型,只需让 AB 实现相同的接口。或者,在 A 中放置一个存根方法,让 B 可以覆盖它。 - Matt Ball
@Skeet 通常声明 List<Foo> 或者更宽松的约束,比如 Collection<Foo> 或者 Iterable<Foo> 是一个很好的实践。正如我在之前的评论中所说:不要担心对象的类型。开始思考你可以用它做什么。 - Matt Ball
+1 感谢,Matt 和 Hovercraft,我会记住的,好答案。 - TeaCupApp

3
除了 @Matt Ball@Hovercraft Full Of Eels 提供的答案,您还可以通过在超类中将子类实现的方法声明为抽象方法来避免必须进行显式转换。
public abstract class A{
    .
    .
    public abstract int getSpec();
}

编辑 -

@Kublai Khan所提到的,接下来需要将超类变为抽象类。


1
+1,不要忘记A现在需要成为一个抽象类。 - Paul Bellora

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