【问题标题】:Why can't I explicitly pass the type argument to a generic Java method?为什么我不能将类型参数显式传递给泛型 Java 方法?
【发布时间】:2010-09-06 16:51:02
【问题描述】:

我已经定义了一个 Java 函数:

static <T> List<T> createEmptyList() {
    return new ArrayList<T>();
}

一种叫法是这样的:

List<Integer> myList = createEmptyList(); // Compiles

为什么我不能通过显式传递泛型类型参数来调用它? :

Object myObject = createEmtpyList<Integer>(); // Doesn't compile. Why?

我从编译器收到错误Illegal start of expression

【问题讨论】:

  • Cheekysoft 解释了原因,但如果你真的觉得需要添加第二种类型 def,只需在静态函数调用之前添加类名: List myList = MyClass.createEmptyList() ;

标签: java generics syntax


【解决方案1】:

当 java 编译器无法自行推断静态方法的参数类型时,您始终可以使用完整的限定方法名称来传递它: Class 。 method();

Object list = Collections.<String> emptyList();

【讨论】:

  • 对于非静态方法,您可以使用 this 关键字:Object list = this.&lt;String&gt; emptyList();
【解决方案2】:

如果您将类型作为方法参数传递,则可以。

static <T> List<T> createEmptyList( Class<T> type ) {
  return new ArrayList<T>();
}

@Test
public void createStringList() {
  List<String> stringList = createEmptyList( String.class );
}

方法不能像类型一样被泛化,因此对于具有动态类型泛型返回类型的方法的唯一选择——唷,这是一个拗口的 :-)——将类型作为论据。

有关 Java 泛型的真正出色的常见问题解答,see Angelika Langer's generics 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 ] );
}

【讨论】:

  • -1 这是一个常见的误解,即当没有其他参数让编译器推断泛型类型时,需要将类文字传递给泛型方法。真正需要的是Xavier's answer 中提到的语法。无论如何,正如Henrik's answer 所提到的,当一个新的泛型对象被立即分配给一个变量时,没有真正的用例来指定它的类型参数——从那时起,只有该变量的类型才重要,即使在编译时也是如此。这就是 Java 7 的 &lt;&gt; 语法背后的原因。
  • 你不使用参数type,所以不应该传递它
  • 这会给出警告“从未使用过类型”,所以最好让自动编译类型推断发生
【解决方案3】:

@pauldoo 是的,你说得很对。这是 java 泛型恕我直言的弱点之一。

我对 Cheekysoft 的回应我想建议也看看它是如何由 Java 人自己完成的,例如 T[] AbstractCollection#toArray(T[] a)。我认为 Cheekysofts 版本更胜一筹,但 Java 版本的优势在于熟悉。

编辑:添加链接。 重新编辑:在 SO 上发现了一个错误 :)


对 Cheekysoft 的跟进: 好吧,由于它是应该返回的某种类型的列表,因此相应的示例应该如下所示:

static <T> List<T> createEmptyList( List<T> a ) {
  return new ArrayList<T>();
}

但是是的,传递类对象显然是更好的方法。我唯一的论点是熟悉度,在这个确切的例子中,它并不值钱(事实上它很糟糕)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多