真的需要通配符泛型吗?

lov*_*ing 13 java generics

例如:

    public String add(Set<?> t){
    ...;
    }



    public <T> String add(Set<T> t){
    ...;
    }
Run Code Online (Sandbox Code Playgroud)

第一个使用通配符泛型; 第二种是通用方法的正常形式.有什么不同?

在什么情况下我们需要通配符泛型,而不是普通的泛型?

new*_*cct 12

这是需要通配符的情况.此方法采用a List<List<?>>,即列表列表.该方法可以向其中添加不同组件类型的列表:

public void foo(List<List<?>> t) {
    t.add(new ArrayList<String>());
    t.add(new ArrayList<Integer>());
}
Run Code Online (Sandbox Code Playgroud)

您不能使用没有通配符的泛型类型参数来执行此操作.例如,以下内容不起作用:

public <T> void foo(List<List<T>> t) {
    t.add(new ArrayList<String>()); // does not compile
    t.add(new ArrayList<Integer>()); // does not compile
}
Run Code Online (Sandbox Code Playgroud)


Mic*_*ski 11

由于添加了对泛型的支持,因此使用参数化类型而不提供类型参数通常会导致编译器警告.另一方面,有些情况下你根本不关心类型参数是什么(即你不在任何地方使用这种类型),或者更糟糕的是,你可能根本不知道什么T是什么,并且使用<?>让你表达这一点而不会导致编译器警告.

"不关心"案例的可能用例(为简洁起见非常简单,但你明白了):

public void clearList(List<?> list) {
    list.clear();
}
Run Code Online (Sandbox Code Playgroud)

"不知道"案例的一个例子:来自Class类的实际方法签名:

static Class<?> forName(String className);
Run Code Online (Sandbox Code Playgroud)

这里该方法返回某种Class类型的对象.Class是通用的但当然你不知道类型,因为它取决于className在运行时解析的参数.所以你不能放在T这里因为T在编译时不知道(即使对于特定的调用站点),并且仅使用Class不带类型参数将是一种不好的做法并导致编译器警告.

  • @DavidWallace:这两个完全不同.`Class <?> forName(String className);`返回未知参数的`Class`.`<T> Class <T> forName(String className);`返回调用者想要的任何参数的`Class`(不知道该参数是什么).这显然不可能安全地实现,除非它总是返回"null". (6认同)

rzy*_*mek 0

调用方法没有区别。

在第二种方法 ( add(Set<T>)) 中,您可以创建类型的变量T

public <T> String add(Set<T> t){
    T item = t.iterator().next();
    //....
}
Run Code Online (Sandbox Code Playgroud)

这为您提供了一些额外的类型检查。在第一种方法中,您只能使用Object.

  • 当然可以,但这并不能回答问题。问题是什么情况下需要通配符;换句话说,我们是否可以使用通配符做一些其他语法不起作用的事情。 (3认同)