为什么我不能显式地将类型参数传递给泛型Java方法?
我定义了一个Java函数:
static <T> List<T> createEmptyList() { return new ArrayList<T>(); }
一种调用方式是这样的:
List<Integer> myList = createEmptyList(); // Compiles
为什么不能通过显式传递泛型类型参数来调用它? :
Object myObject = createEmtpyList<Integer>(); // Doesn't compile. Why?
我从编译器收到错误"表达式的非法开头"。
解决方案
回答
自从我深入研究Java的各个部分以来已经有一段时间了,但是...
为什么我们不能这样做,可能是语言开发人员的设计选择。尽管如此,由于Java使用的类型擦除,泛型信息总会在编译时被丢弃,因此在示例中,无论我们是否具有类型参数,它都会创建完全相同的字节码。
回答
如果将类型作为方法参数传递,则可以。
static <T> List<T> createEmptyList( Class<T> type ) { return new ArrayList<T>(); } @Test public void createStringList() { List<String> stringList = createEmptyList( String.class ); }
不能以与类型相同的方式来泛化方法,因此,对于具有动态类型的泛型返回类型-phew的方法,唯一的选择是:-)-将类型作为参数传递。
有关Java泛型的真正优秀的FAQ,请参阅Angelika Langer的泛型FAQ。
。
。
跟进:
在这种情况下,像在Collection.toArray(T [])中那样使用数组参数是没有意义的。使用数组的唯一原因是因为使用相同(预分配)的数组来包含结果(如果数组足够大以适合所有结果)。这样可以节省在运行时始终分配新数组的时间。
但是,出于教育目的,如果我们确实想使用数组类型,则语法非常相似:
static <T> List<T> createEmptyList( T[] array ) { return new ArrayList<T>(); } @Test public void testThing() { List<Integer> integerList = createEmptyList( new Integer[ 1 ] ); }
回答
@pauldoo
是的,你说的很对。这是java泛型imho的弱点之一。
我想对Cheekysoft做出回应,我还建议考虑一下Java人员自己是如何完成的,例如T [] AbstractCollection#toArray(T [] a)。我认为Cheekysofts版本更好,但是Java拥有熟悉的优势。
编辑:添加了链接。
重新编辑:在SO上发现一个错误:)
Cheekysoft的后续行动:
好吧,因为它是应该返回的某种类型的列表,所以相应的示例应类似于:
static <T> List<T> createEmptyList( List<T> a ) { return new ArrayList<T>(); }
但是可以,通过类对象显然是更好的选择。我唯一的论点是熟悉,在这个确切的例子中,它并不值钱(实际上是不好的)。
回答
当Java编译器无法自行推断静态方法的参数类型时,我们始终可以使用完整的合格方法名称Class来传递它。 <类型> method();
Object list = Collections.<String> emptyList();