为什么Class <?>优于Class
收藏

如果我将Class声明为字段:

Class fooClass;

Eclipse给我警告:

类是原始类型。泛型类型Class的引用应参数化

实际上这是什么意思?我为什么要这么做呢?如果我要求Eclipse提供“快速修复”,它将给我:

Class<?> fooClass;

这似乎并没有增加太多价值,但不再发出警告。

EDIT: Why is Class generic? Could you please give an example of parameterization, i.e. could there be a valid use of something other than <?> ?

编辑:哇!我还没有意识到这一点。我也看过Java拼图游戏,这肯定使我害怕熊陷阱。所以我会一直使用

Class<MyString> myStringClass = MyString.class;

而不是

Class myStringClass = MyString.class;

(但是从第一天开始使用Java以来​​,我并没有真正注意到Class何时成为泛型)。

NOTE: I have accepted @oxbow_lakes as this makes sense to me, but it is clearly a very complicated area. I would urge all programmers to use the specific Class<MyString> rather than Class. And Class<?> is much safer than Class.

最佳答案

原始类型和无界通配符

None of the previous answers have really addressed why you should prefer Class<?> over Class, as on the face of it, the former seems to offer no more information than the latter.

The reason is that, the raw type, i.e. Class, prevents the compiler from making generic type checks. That is, if you use raw types, you subvert the type-system. For example:

public void foo(Class<String> c) { System.out.println(c); }

可以这样调用(它将同时编译和运行):

Class r = Integer.class
foo(r); //THIS IS OK (BUT SHOULDN'T BE)

但不是:

Class<?> w = Integer.class
foo(w); //WILL NOT COMPILE (RIGHTLY SO!)

By always using the non-raw form, even when you must use ? because you cannot know what the type parameter is (or is bounded by), you allow the compiler to reason about the correctness of your program more fully than if you used raw types.

为什么根本没有原始类型?

Java语言规范说:

仅允许使用原始类型作为对遗留代码的兼容性的让步

You should always avoid them. The unbounded wildcard ? is probably best described elsewhere but essentially means "this is parameterized on some type, but I do not know (or care) what it is". This is not the same as raw types, which are an abomination and do not exist in other languages with generics, like Scala.

为什么要对类进行参数化?

好吧,这是一个用例。假设我有一些服务接口:

public interface FooService

我想使用系统属性来定义要使用的类,以注入其实现。

Class<?> c = Class.forName(System.getProperty("foo.service"));

在这一点上,我不知道我的班级是正确的类型:

//next line throws ClassCastException if c is not of a compatible type
Class<? extends FooService> f = c.asSubclass(FooService.class); 

Now I can instantiate a FooService:

FooService s = f.newInstance(); //no cast

    公众号
    关注公众号订阅更多技术干货!