为什么 Class<?> 比 Class 更受优

2022-09-01 03:08:32

如果我将类声明为字段:

Class fooClass;

Eclipse给了我警告:

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

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

Class<?> fooClass;

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

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

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

Class<MyString> myStringClass = MyString.class;

而不是

Class myStringClass = MyString.class;

(但是从第一天开始使用Java,我并没有真正注意到Class何时成为通用的);

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


答案 1

原始类型和无界通配符

前面的答案都没有真正解决为什么你应该更喜欢 ,因为从表面上看,前者似乎没有提供比后者更多的信息。Class<?>Class

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

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!)

通过始终使用非原始形式,即使由于无法知道类型参数是什么(或受其限制)而必须使用,也可以允许编译器比使用原始类型更充分地推理程序的正确性。?


为什么有原始类型?

Java语言规范说:

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

您应该始终避免使用它们。无界通配符可能最好在其他地方描述,但本质上意味着“这是在某种类型上参数化的,但我不知道(或关心)它是什么”。这与原始类型不同,原始类型是一种令人憎恶的类型,在具有泛型的其他语言中不存在,例如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); 

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

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

答案 2

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

你是对的。但这可能会增加价值:

Class<FooClass> fooClass;

或者,如果更合适:

Class<? extends FooClass> fooClass;

Class<FooInterface> fooClass;

与一般的泛型一样,可以通过指定希望变量包含的类的类型来提高类型安全性。针对原始类型的警告只是为了捕获未使用此潜力的代码段。通过声明你基本上是在说“这是为了举行任何类型的课程”。Class<?>


推荐