为什么Class <?>比Class更受欢迎

pet*_*ust 30 java generics raw-types

如果我将一个类声明为一个字段:

Class fooClass;
Run Code Online (Sandbox Code Playgroud)

Eclipse给了我警告:

类是原始类型.应该对泛型类的引用进行参数化

这在实践中意味着什么?我为什么要这么做呢?如果我要求Eclipse进行"快速修复",它会给我:

Class<?> fooClass;
Run Code Online (Sandbox Code Playgroud)

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

编辑:为什么Class通用?能否举一个参数化的例子,即是否可以有效地使用其他东西<?>

编辑:哇!我没有意识到这个的深度.我也看过Java Puzzler,它肯定让我害怕熊陷阱.所以我会一直使用

Class<MyString> myStringClass = MyString.class;
Run Code Online (Sandbox Code Playgroud)

而不是

Class myStringClass = MyString.class;
Run Code Online (Sandbox Code Playgroud)

(但是从第一天起就使用了Java,我没注意到Class何时成为泛型);

注意:我接受了@oxbow_lakes,因为这对我来说很有意义,但它显然是一个非常复杂的领域.我会敦促所有程序员使用特定的Class<MyString>而不是Class.而且Class<?>比安全得多Class.

oxb*_*kes 46

原始类型和无界通配符

以前的答案都没有真正解决,为什么你应该更喜欢Class<?>Class,因为在它的面前,前者似乎提供不超过后者的更多信息.

原因是,原始类型,即Class阻止编译器进行泛型类型检查.也就是说,如果使用原始类型,则会破坏类型系统.例如:

public void foo(Class<String> c) { System.out.println(c); }
Run Code Online (Sandbox Code Playgroud)

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

Class r = Integer.class
foo(r); //THIS IS OK (BUT SHOULDN'T BE)
Run Code Online (Sandbox Code Playgroud)

但不是:

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

通过始终使用非原始表单,即使您必须使用?因为您无法知道类型参数是什么(或受限制),您允许编译器比使用原始类型更充分地推断程序的正确性.


为什么要有原始类型?

Java语言规范说:

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

你应该总是避免它们.无界的通配符?可能在别处最好描述,但实际上意味着"这是在某种类型上参数化,但我不知道(或关心)它是什么".这与原始类型不同,原始类型是令人厌恶的,并且在其他语言中不存在,如Scala.


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

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

public interface FooService
Run Code Online (Sandbox Code Playgroud)

我想注入它的实现,使用系统属性来定义要使用的类.

Class<?> c = Class.forName(System.getProperty("foo.service"));
Run Code Online (Sandbox Code Playgroud)

我现在还不知道我的班级是正确的类型:

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

现在我可以实例化一个FooService:

FooService s = f.newInstance(); //no cast
Run Code Online (Sandbox Code Playgroud)

  • +1到目前为止唯一的答案实际上回答了问题! (3认同)