通用参数作为变量 - Java

时间:2011-08-27 05:02:32

标签: java generics variables type-safety

构造函数NotePanel(itemClass)引用缺少的类型itemClassI具有类NotePanel<T extends AbstractNoteItem> extends JPanel,并且在单独的类中返回应该在方法期间创建的NotePanel的方法:

public class NoteList extends JList {
    ...
    public class NoteListModel extends AbstractListModel {
        ...
        public NotePanel getPanelFromIndex(int index) {
            if (!indexExists(index)) {
                // FYI, indexExists(int) works fine
                return null;
            } else {
                AbstractNoteItem item = getElementAt(index);
                // FYI, getElementAt(int) works fine
                assert (item != null);  
                Class<?> itemClass = item.getClass();
                return (new NotePanel<itemClass> (item));
            }
        }
    }
}

返回新NotePanel的行上有一个错误:“构造函数NotePanel(itemClass)引用缺少的类型itemClass。”有人可以告诉我如何使这项工作?

如果这个代码不够,我很乐意提供更多代码。我的所有进口都是有序的(谢谢,组织进口!)。我没有看到任何明显的问题,但我也是使用泛型的新手。

提前致谢!

4 个答案:

答案 0 :(得分:4)

您尝试做的事情不起作用,因为泛型类型参数仅在编译时存在;由于类型擦除,它们在运行时没有任何影响。因此,将在运行时获得的Class<?>用作泛型类型参数是没有意义的。

如果你不想知道为什么NotePanel首先是通用的,那就很难建议一个合适的选择。

答案 1 :(得分:1)

您只能使用常量通用参数。在这里,可以像AbstractNoteItem一样紧,但不能更窄。

可能,做

new NotePanel<AbstractNoteItem> (item)

会没事,你想要什么,但没有看到全局,很难说肯定。

此外,您的返回类型是普通的NotePanel,因此参数化其构造并不重要;无论你将它归还给谁都不会看到参数化。

正如另一个答案中所提到的,关键是Java Generics仅在编译时。它们不像生成不同代码的C ++模板,它只是一种更奇特的编译时类型检查形式。

答案 2 :(得分:0)

以下可能有效,也可能无效。这是关于generic methods的教程。

public class NoteList extends JList {
    ...
    public class NoteListModel extends AbstractListModel {
        ...
        public < T extends AbstractNoteItem > NotePanel < T > getPanelFromIndex(int index) {
            if (!indexExists(index)) {
                // FYI, indexExists(int) works fine
                return null;
            } else {
                T item = ( T ) ( getElementAt(index) ) ; // this should generate a warning
                // FYI, getElementAt(int) works fine
                assert (item != null);  
                // not needed // Class<?> itemClass = item.getClass();
                return (new NotePanel<T> (item));
            }
        }
    } }

调用方法

class NoteItemImpl extends AbstractNoteItem { ... stuff ... }

Notelist notelist ; 
// implicit type argument specification
NotePanel < AbstractNoteItem > n1 = notelist . getPanelFromIndex ( 1 ) ;  
NotePanel < NoteItemImpl > n2 = notelist . getPanelFromIndex (2 ) ; // may generate class cast exception

// explicit type argument specification
NotePanel < AbstractNoteItem > n3 = notelist . < AbstractNoteItem > getPanelFromIndex ( 3 ) ;
NotePanel < NoteItemImpl > n4 = notelist . < NoteItemImpl > getPanelFromIndex ( 4 ) ; // may generate class cast exception

答案 3 :(得分:0)

如果我正确理解了这个问题,那么你有一个NotePanel类,它有一个音符项成员。此注释项是AbstractNoteItem的子类。但是您不希望将注释项指定为AbstractNoteItem类型,因为您希望直接访问子类方法。

现在,如果所有这些子类方法具有相同的名称和相同的签名(跨层次结构),那么您根本不需要泛型;普通的旧多态将适合你。

但是如果子类方法完全不同,那么你想要的是单独的NotePanel类,每种类型的注释项都有一个。在您的问题中,您似乎想要使用泛型生成它们。由于擦除,这在Java中实际上是不可能的。正如另一个答案所提到的,C ++泛型将创建多个类,但是你不能用Java来实现它。

但是如果这些单独的NotePanel类都有方法在每个AbstractNoteItem子句中调用了不同的方法,那么我认为你真的需要编写单独的NotePanel子类!如果需要,这种并行的类层次结构并不是那么糟糕。

如果您选择此路线,请使用工厂方法替换对NoteItem构造函数(您无法工作的构造函数)的调用,以创建正确类型{{ 1}}子类。