为什么这个Java泛型代码不能正常工作?

时间:2014-04-13 17:00:43

标签: java generics

我有以下代码:

public abstract class Heap {

    Comparable<?> data[];

    int count, size;

    public Heap( int size ) {

        this.size = size;

        data = new Comparable<?>[ size + 1 ];

        this.count = 0;
    }

    public abstract void insert( Comparable<?> item );

}

class MinHeap extends Heap {

    public MinHeap (int size ) { super(size); }

    public void insert( Comparable<?> item ) {

        //this line here is giving me an error 
        //due to how I am storing the array in Heap

        int k = data[ 0 ].compareTo(  item );

    }
}

上面指出的行给了我这个错误:The method compareTo(capture#1-of ?) in the type Comparable<capture#1-of ?> is not applicable for the arguments (Comparable<capture#2-of ?>)。在维持这些条件时,我无法找到使其工作的方法:1)我希望MinHeap使用任何实现Comparable的数据,2)我不想将预先初始化的数组传递给构造函数。我这样说是因为我不想做以下事情:

abstract class Heap< T extends Comparable<T> > {

       T data[];

       public Heap( T data[], int size ) {

             this.data = data; 
    //I do not want to have to pass an instantiated array. 
    //I want the constructor to handle the instantiation. If I do this I know the issue with the 
    //compareTo will be solved, but I really prefer to avoid this.
       }

}

我的问题是:在我的代码中,为什么我会收到此错误?有没有人知道除了第二个例子中描述的方式之外的方式?我希望能够创建具有任何可比数据的最小堆数据结构。所有有用的评论都表示赞赏。谢谢。

附注:不要担心实例变量的访问修饰符。为简单起见,我将它们保留为默认值我知道他们应该是私人的setter / getters或protected。

3 个答案:

答案 0 :(得分:1)

首先,此代码对于创建通用数组无效:

data = new Comparable<?>[ size + 1 ];

This link in the Java Trails解释了为什么它是非法的,但它归结为数组必须在编译时知道它们的类型,并且泛型基于类型擦除而工作,并且可以在运行时推断。

但在我们解决这个问题之前,您的仿制药存在问题 - 它们并非真正......通用。您只在此使用通配符通用,没有边界。

如果你想让你的抽象类包含一个充满Comparable的泛型数组,那么你希望你的抽象类绑定到Comparable<T>,并让你的数据被绑定到T。有了这个,我们最终可以将数组初始化修复为可编译(但未经检查的强制转换)形式:

data = (T[]) new Comparable[size + 1];

这里是完整的课程供参考。它会关闭到您的第二个表单,并且不要求您传入实例化的数组。此外,由于T绑定到Comparable<T>,我们不需要将其声明为方法中的参数 - 我们只需提供T

public abstract class Heap<T extends Comparable<T>> {
    T data[];
    int count, size;

    public Heap(int size) {
        this.size = size;
        data = (T[]) new Comparable[size+1];
        this.count = 0;
    }

    public abstract void insert(T item);

}

除此示例之外,您还希望将泛型类型添加到子类中:

class MinHeap<T extends Comparable<T>> extends Heap<T>    

答案 1 :(得分:1)

试试这个:

  • 首先compareTo()返回int而不是boolean值。
  • public abstract void insert( Comparable<?> item );错了。
  • 在通用而非静态数组的情况下使用List。有关详细信息,请参阅How to create a generic array?

示例代码:

abstract class Heap<T> {
    List<Comparable<T>> data;

    public Heap(int size) {
        data = new ArrayList<Comparable<T>>();
    }

    public abstract void insert(T item);
}

class MinHeap<T extends Comparable<T>> extends Heap<T> {

    public MinHeap(int size) {
        super(size);
    }

    public void insert(T item) {
        int k = data.get(0).compareTo(item);
    }
}

答案 2 :(得分:0)

您的数据可以包含任何类型的对象,只要它的类实现Comparable即可。所以你可以在数组中包含字符串,整数,长整数或香蕉。

将整数与字符串或香蕉进行比较并不合理。这就是编译器不能编译此代码的原因。

第二种方式是正确的方式。您可以在内部使用对象数组,并将每个对象强制转换为T。如果所有方法只接受T的实例,则保证转换成功。或者你可以使用List,它比数组更加通用。