如何在子类中更改变量的实现?

时间:2013-05-27 20:25:44

标签: java inheritance collections

在基类中,我有一个实现为ArrayList的变量:

class Base<E> {

    List<Collection<E>> adj;

    public Base (int size) {
        adj = new ArrayList<Collection<E>>(size);
        for(int i = 0; i < size; i++)
            adj.add(new ArrayList<E>());
    }
}

现在在子类中,我想将实现更改为HashSet:

class Sub<E> extends Base<E> {

    List<Collection<E>> adj;

    public Sub (int size) {
        adj = new ArrayList<Collection<E>>(size);
        for(int i = 0; i < size; i++)
            adj.add(new HashSet<E>());
    }
}

但它不会让我,因为它给了我一个“必须明确唤起另一个构造函数”的错误。我该怎么办?

3 个答案:

答案 0 :(得分:1)

好吧,如果它告诉你调用另一个构造函数,你应该尝试调用另一个构造函数。

public Sub (int size) {
   super(size); // invoke superclass constructor
   adj = new ArrayList<Collection<E>>(size);
   for(int i = 0; i < size; i++)
   adj.add(new HashSet<E>());
}

是的,我知道这不是一个理想的解决方案。我有空的时候会修改这个。

答案 1 :(得分:1)

虽然有些人已经回答了这个问题,但是他们错过了更大更重要的一点:不要影响基类成员!可能有一两种罕见的情况,你有充分的理由这样做,但我想不出任何。但这是一个常见的初学者错误。

轻松演示问题:

private static class Foo {
    protected int x = 1;
}

private static class Bar extends Foo {
    protected int x = 0;
}

public static void main(String[] args) {
    Bar b = new Bar();
    Foo f = b;
    System.out.println(b.x); // prints 0
    System.out.println(f.x); // prints 1
}

在你的例子中,你真的不希望你的班级中有两个包含不同内容的“相同”名称的列表。解决方案很简单:使基类中的成员受到保护(否则您只能在同一个包中进行子类化)并删除子类中的声明。

关于构造函数问题:这很简单但有两部分:如果在构造函数中没有显式编写任何super调用,编译器会自动在代码中插入super()调用。 此外,如果你不编写自己的任何构造函数,编译器会生成一个参数less constructor,尽管你没有自动生成这样的构造函数。由于您的Base类有一个带有int的构造函数,因此当您不编写显式超级调用时,编译器会生成对super()的调用,该调用不存在。

如果在基类中编写无参数构造函数,则代码将编译并隐式调用此代码。这是一个坏主意,因为你想让你的基类知道用户想要的大小,所以你真正想要的是调用super(size)

答案 2 :(得分:0)

这就是Java构造对象的方式。第一件事(在一些静态初始化之后)子类的构造函数是构造超类。 Java通过调用超类的默认构造函数自动完成此操作。默认构造函数始终是不带参数的构造函数。所以在你的情况下,这将是:

public Base() {
  // do construction work here
} 

现在,由于您的超类没有默认构造函数,Java不知道用于构造超类的构造函数。

所以要么你添加一个默认构造函数,然后调用你的专用构造函数,如:

public Base () {
  this(4); // default value for example
}

public Base (int size) {
   adj = new ArrayList<Collection<E>>(size);
   for(int i = 0; i < size; i++)
     adj.add(new ArrayList<E>());
}
或者,就像@Zong li所说的那样,并在您的专门构造函数中明确地调用您的super(size)构造函数。因为在这种情况下你想要完全覆盖构造函数,所以我将选择一个空的无参数(默认)构造函数。