给定 AGenericClass
声明如下:
public class AGenericClass<T> {
T subject;
public void setSubject(T subject) {
this.subject = subject;
}
}
变量a、b和c之间有什么区别?
AGenericClass<String> a = new AGenericClass<>();
AGenericClass<?> b = new AGenericClass<String>();
AGenericClass c = new AGenericClass<String>();
a.setSubject("L"); // OK.
b.setSubject("M"); // Error: setSubject(capture<?>) cannot be
// applied to (java.lang.String)
c.setSubject("N"); // Warning: Unchecked call to 'setSubject(T)'
// as a member of raw type 'AGenericClass'
a b 和 c 都是在 IDE 没有提示的情况下声明的,但是当 setSubject
被调用。
最佳答案
这三者之间的差异很大程度上与您在编译时获得的检查有关。鉴于泛型旨在保护用户免受运行时不安全转换的影响,因此它们之间的关键和主要差异就 Root 于此。
AGenericClass<String>
声明类型为 String
的泛型类实例.使用此泛型完成的任何需要泛型参数的操作都会将该参数绑定(bind)到 String
,并将在编译时强制执行类型检查和类型安全。
也就是说,如果你有AGenericClass<String> a = new AGenericClass<>();
你试着调用a.setSubject(3)
, Java 将不允许应用程序编译,因为类型不匹配。
AGenericClass<?>
声明具有未知 类型的泛型类的实例。正式地,?
是一个通配符,它可以是任何类型,可以如果您想从中检索元素,但不是如果您想要从中添加元素。
原因是什么? AGenericClass<?>
实际上是 AGenericClass<? extends Object>
,这很重要,因为 in and out principle .通常(虽然这不是严格保证),任何与 extends
通用的东西意味着只读操作。
正如我之前所说,从中读取很好,因为保证您的类(class)至多是Object
,但是您不能写入它,因为您不知道,也不能保证,您从任何给定的调用中添加了什么样的对象。
AGenericClass
没有 类型声明是原始类型。 You can read more about them here ,但要知道它们的存在是出于遗留兼容性原因。如果您的代码使用原始类型,您将失去编译时检查并且您的代码可能最终会抛出 ClassCastException
。在运行时,调试、诊断和解决要困难得多。
关于java - 这三个参数化变量有何不同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36052041/