这三个参数化变量有何不同?

Ste*_*hen 6 java generics

鉴于AGenericClass如下:

public class AGenericClass<T> {
  T subject;
  public void setSubject(T subject) {
    this.subject = subject;
  }
}
Run Code Online (Sandbox Code Playgroud)

变量a,bc之间什么区别?

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'
Run Code Online (Sandbox Code Playgroud)

a bc all都是在没有IDE控制的情况下声明的,但是在setSubject调用时它们的行为都不同.

Mak*_*oto 3

三者之间的差异很大程度上与编译时进行的检查有关。鉴于泛型旨在保护用户在运行时免受不安全的强制转换,因此它们之间的关键和主要差异就源于此。


AGenericClass<String>声明具体类型为 的泛型类的实例String。使用此泛型完成的任何需要泛型参数的操作都将绑定该参数,并在编译时String强制执行类型检查和类型安全。

也就是说,如果您AGenericClass<String> a = new AGenericClass<>();尝试调用a.setSubject(3),Java 将不允许应用程序编译,因为类型不匹配。

AGenericClass<?>声明具有未知类型的泛型类的实例。形式上,?是一个通配符,它​​可以是任何类型,如果您想从中检索元素,则可以,但如果您想从中添加元素,则不行。

原因? AGenericClass<?>实际上AGenericClass<? extends Object>,这很重要,因为进出原则。一般来说(尽管这不是严格的保证),任何通用的 with 都extends意味着只读操作。

正如我之前所说,读取是很好的,因为你可以保证一个最多是an 的类Object,但你不能写入它,因为你不知道,也不能保证你是什么样的对象。从任何给定的调用中添加到它。

AGenericClass 没有类型声明的是原始类型。 您可以在此处阅读有关它们的更多信息,但要知道它们的存在是出于遗留兼容性原因。如果您的代码使用原始类型,您将丢失编译时检查,并且您的代码可能会在运行时抛出异常ClassCastException,这将更加难以调试、诊断和解决。