为什么是Class<?>首选Class [英] Why is Class<?> preferred to Class

查看:157
本文介绍了为什么是Class<?>首选Class的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  Class fooClass; 

Eclipse给了我警告:


类是一种原始类型。对
泛型类型的引用应该是
参数化的

这在实践中意味着什么?我为什么要求这样做?如果我问Eclipse快速修复,它给了我:

  Class<?> fooClass; 

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



编辑:为什么类通用?请给出一个参数化的例子,也就是说,除了<?>



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

  Class< MyString> myStringClass = MyString.class; 

而非

  Class myStringClass = MyString.class; 

(但是从第一天开始使用Java,我没有真正注意到Class变得通用)。

注意:我已经接受@oxbow_lakes,因为这对我来说很合理,但它显然是一个非常复杂的领域。我会敦促所有程序员使用特定的 Class< MyString> 而不是 Class 。和 Class <?> Class

解决方案

原始类型和无界通配符



以前的答案都没有解决您为什么应该更喜欢 Class <?> over Class ,就像在它的表面上,前者似乎不提供比后者更多的信息。 p>

原因在于,原始类型 Class 阻止编译器进行泛型类型检查。也就是说,如果您使用原始类型,那么 颠覆类型系统。例如:

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

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

 类r = Integer.class 
foo(r); //这是好的(但不应该是)

但不是:

  Class<?> w = Integer.class 
foo(w); //不会编译(正确)!

通过始终使用非原始格式,即使在您必须使用,因为您无法知道类型参数是什么(或受限于),您可以让编译器更全面地推断程序的正确性使用原始类型。






为什么需要原始类型?



Java语言规范说:


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


你应该总是避免它们。无界通配符可能是其他地方最好的描述,但本质上意味着这是在某种类型上进行参数化的,但我不知道(或关心)它是什么 / em>的。这与 raw types 不一样,它是一种可憎的东西,在其他带泛型的语言中不存在,比如 Scala






为什么Class参数化?



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

  public interface FooService 

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

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

我现在还不知道我的类是正确的类型 em>:

  //下一行抛出ClassCastException,如果c不是兼容类型
Class <?扩展FooService> f = c.asSubclass(FooService.class);

现在我可以实例化一个 FooService

  FooService s = f.newInstance(); //无法转换


If I declare a Class as a field:

Class fooClass;

Eclipse gives me the warning:

Class is a raw type. References to generic type Class should be parametrized

What does this mean in practice? and why am I urged to do it? If I ask Eclipse for a "quick fix" it gives me:

Class<?> fooClass;

which doesn't seem to add much value but no longer gives a warning.

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 <?> ?

EDIT: WOW! I had not realized the depths of this. I have also watched the Java Puzzler and it's certainly scared me about the bear traps. So I will always use

Class<MyString> myStringClass = MyString.class;

rather than

Class myStringClass = MyString.class;

(But having used Java from day one, I didn't really notice when Class became generic);

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.

解决方案

Raw Types and Unbounded Wildcards

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); }

Can be called thusly (it will both compile and run):

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

But not by:

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.


Why have Raw Types at all?

The Java Language Specification says:

The use of raw types is allowed only as a concession to compatibility of legacy code

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.


Why is Class Parameterized?

Well, here is a use-case. Suppose I have some service interface:

public interface FooService

And I want to inject an implementation of it, using a system property to define the class to be used.

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

I do not know at this point that my class, is of the correct type:

//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

这篇关于为什么是Class&lt;?&gt;首选Class的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆