0

在一个基类中,我有一个作为 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>());
    }
}

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

4

3 回答 3

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()调用插入到您的代码中。此外,如果您不编写自己的任何构造函数,编译器会生成一个无参数构造函数,尽管这样的构造函数不会自动生成。由于您的 Base 类有一个采用 int 的构造函数,因此当您不编写显式超级调用时,编译器会生成一个super()不存在的调用。

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

于 2013-05-27T21:24:17.467 回答
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>());
}

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

于 2013-05-27T20:27:34.030 回答
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)从您的专用构造函数中显式调用您的构造函数。由于在这种情况下您想完全覆盖构造函数,所以我选择一个空的无参数(默认)构造函数。

于 2013-05-27T21:05:02.227 回答