如何正确使用Java泛型来实现ADT的数组实现

时间:2014-03-12 16:03:04

标签: java arrays generics adt

我正在尝试教我的学生使用Java泛型的正确方法。我正在教一个数据结构课程,所以我希望他们使用数组和他们自己的链表,而不是Java Collections(例如没有ArrayList)。典型问题是为ADT提供阵列实现。下面是一个示例,我尝试使用实现为数组的堆来提供优先级队列。我想支持任何类型的数据对象的优先级队列,所以我使用泛型 我从界面开始:

public interface PriQue<E> {
    void insert(int pri, E data);
    E remove(); // return null when empty
    boolean isEmpty();
}

然后我实施了它:

public class ArrayHeap<E> implements PriQue<E> {
//private class Entry<E> {  hides E of ArrayHeap which means remove fails
    private class Entry {  // uses E of ArrayHeap
        int pri;
        E data;
    . . .
    } // end of Entry
    Entry heap[];
    int cnt;
    public ArrayHeap(int size) {
        // heap = new Entry[size]; can not create generic array error
        // heap = (Entry[])new Object[size]; blows up on a cast error
        heap = (Entry[])new Object[size];
        cnt = 0;
    }
    . . .
    public E remove() {
        E tmp = (E)heap[--cnt].getData(); //bad don't want to cast
        // trickle down code here
        return tmp;
    }

由于接口是参数化的,我在实现类中使用相同的泛型 - 我认为这没关系。 我需要创建一个包含优先级的条目数组和相应的数据项。所以我创建了一个私有类。我的问题开始了。如果我将参数保留,那么因为它是ArrayHeap的一部分,所以它应该在那里选择E通用形式。当我尝试创建一个Entry数组时,这会编译但会爆炸。或者,我可以为Entry提供一个显式的通用参数。如果我选择E,它将从ArrayHeap中“隐藏”E,当我尝试从数组中删除E时,它没有意识到它与ArrayHeap E是相同的E。如果我将其命名为其他,比如说V,则它不能将E分配给V,我无法存储任何数据。我认为这是实施数据结构的一种相当普遍的情况 我试过阅读http://www.angelikalanger.com/GenericsFAQ/FAQSections/ParameterizedTypes.html#FAQ104 但它没有涵盖嵌套类(并且它主要是关于什么不起作用) 我已经尝试阅读Java集合映射实现的代码,但我看不出有什么不同。

2 个答案:

答案 0 :(得分:3)

这对我有用:

public class ArrayHeap<E> implements PriQue<E> {
    private static class Entry<E> {
        int pri;
        E data;

        // ...

        public E getData() {
            return data;
        }
    }

    Entry<E>[] heap;
    int cnt;

    public ArrayHeap(int size) {
        heap = (Entry<E>[])new Entry<?>[size];
        // or: heap = new Entry[size];
        cnt = 0;
    }

    public E remove() {
        E tmp = heap[--cnt].getData();
        return tmp;
    }

    // ...
}

关键是Entry被改为成为一个静态嵌套类,而不是一个非静态内部类(它仍然依赖于你的外部类的类型参数)。然后你可以实际创建一个Entry<?>的数组,并从那里做一个演员。

答案 1 :(得分:1)

问题是因为Java在编译时擦除了泛型类型参数,所以创建包含泛型类型的数组是不安全的。你需要在某个地方进行演员表演:你能做的最好的事就是把它隐藏在辅助函数中。

例如,如果你看一下ArrayList的JDK实现,你会发现它的核心是Object[]