Java中的Class clazz和Class<?> clazz有什么区别?

11
我需要在Java中使用反射。我知道Class clazz创建一个表示Class对象的变量。然而,我正试图使用forName("aClassName")方法从String引用一个Class对象。我的IDE(Eclipse)似乎更喜欢使用Class<?> clazz符号来声明变量。我在其他地方也看到过这种符号。这是什么意思?

2
这与三元运算符有什么关系?这里没有任何运算符。 - Jon Skeet
在这个上下文中,它不是一个三元操作符,而是一个未绑定的通配符。 - Perception
3个回答

27

Class是一个原始类型 - 它基本上是一个泛型类型,您正在处理它,好像您根本不知道泛型。

Class<?>是使用未绑定通配符的泛型类型 - 它基本上意味着 "Class<Foo>用于某些类型Foo,但我不知道具体是什么".

类似地,您可以使用有界通配符:

  • Class<? extends InputStream>表示"Class<Foo>用于某些类型Foo,但我不知道具体是什么,只要它是InputStream或其子类"

  • Class<? super InputStream>表示"Class<Foo>用于某些类型Foo,但我不知道具体是什么,只要它是InputStream或其超类"

另请参阅Java Generics FAQ以获取更多信息:

以及Java语言规范:

特别是从未经处理的类型部分:

原始类型与通配符密切相关,两者都基于存在类型。可以将原始类型视为其类型规则故意不健全以适应遗留代码交互的通配符。历史上,原始类型先于通配符出现;它们最初在GJ中引入,并在Gilad Bracha,Martin Odersky,David Stoutamire和Philip Wadler的论文《为过去增加泛型:将来的安全性》中描述,《ACM面向对象编程,系统,语言和应用会议记录(OOPSLA 98)》,发布于1998年10月。

但是,从技术上讲,原始类型和未限定通配符之间实际上没有任何区别,对吧?我的意思是除了避免编译器警告和可能提高代码可读性之外。 - Gothmog
1
@Gothmog:有些情况下,由于原始类型的处理方式(如果我没记错的话),它可能会影响覆盖和重载。 - Jon Skeet

2

首先要认识到的是,在这种情况下,"?"不是三元运算符,而是Java泛型实现的一部分,并表示Class类型未指定,正如其他答案中已经解释的那样。

为了澄清关于三元运算符的问题,其实非常简单。

想象一下你有以下if语句:

boolean correct = true;
String message;

if (correct) {
  message = "You are correct.";
} else {
  message = "You are wrong.";
}

你可以使用三元运算符(将其视为if-else的快捷方式)来重写它:

message = (correct) ? "You are correct." : "You are wrong.";

然而,为了提高代码的可读性,最好只在最简单的语句中使用三元运算符。


我明白了,之前我以为?一直被称为三元操作符。现在我明白这是错误的。三元操作符常用吗?或者这是过去更流行的一个特性? - Andrew Harasta
我认为它仍在使用中,但通常会避免使用。我偶尔还能看到它出现在代码中,所以了解如何阅读它是很好的。在极少数情况下,更简洁的语句可以更清晰地表达正在发生的事情。那大概是唯一考虑使用它而不是if/else的时候。 - yogaphil

0
在泛型类型中,通配符?表示“任何类”(因此Class<?>与参数正确设置的原始类型Class相同)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接