Java 泛型:是与对象的关系

Java generics: is-A relation to Object

我正在尝试了解 泛型 class 及其具体实例的特征,以及 泛型集合的特征 .

假设我定义了一个泛型 class:Stack<T> 现在我正尝试以这种方式使用它:

Stack<String> ts = new Stack<>(5);
Stack<Object> to = new Stack<>(5);
to = ts // compilation error!

很明显 Stack<String> 不是 Stack<Object>

定义通用集合时我感到困惑:

Set<E> elemnts = new Hashset<>();

并注意到我可以使用 elements.toString()!这意味着 Set<E> elemnts 扩展了 Object! 那么这里到底发生了什么?

编译错误并不意味着 String 不是 Object,这是不正确的。例如,下面的代码工作得很好:

String s = "I am String!";
Object o = s;

错误的意思是 Stack<String> 不是 Stack<Object>。例如,您可以在 Stack<Object> 上调用 push(new Object()),但显然不能在 Stack<String>.

上调用

对于以下内容:

Stack<String> ts = new Stack<>(5);
Stack<Object> to = new Stack<>(5);
to = ts // compilation error!

是的,这个编译失败了,因为泛型本质上是编译器强制类型安全的一个特性。就虚拟机而言,他们实际上只有一个Stackclass。

这条语句:

Set<E> elemnts = new Hashset<>();

相当于:

Set<E> elemnts = new Hashset<E>();

该表示法是在 Java 7 中引入的,有时由于 <> 而被称为 'diamond operator'。只是为了去除冗余。

它是扩展对象的集合 class,就像 Java 扩展对象中的所有 classes 一样。

以下内容适用于代码中的 Class 对象:

 boolean b = ts.getClass() == to.getClass();  // b is true

字符串 class 是对象的隐式子class。由于对象 class 是 java 中所有 class 的超级 class。因此下面的陈述是有效的

String x="hello";
Object o= x;

但是 Stack<String> 不是 Stack<Object> 的子 class。因此代码给出编译时错误。

Stack<String> ts = new Stack<>(5);
Stack<Object> to = new Stack<>(5);
to = ts // compilation error!

那么 Java 中的泛型到底是什么?, the generic types are compiler enforcements. To be exact, at runtime, the generic types do not exist anymore. They are replaced by Object or the upper bound of a generic type. This process is called Type Erasure 所述。因此,泛型类型仅在编译时存在。

那为什么我们不能把一个ArrayList<String>转换成一个ArrayList<Object>呢?即使类型参数处于一个关系中(StringObject),通用的 类 没有。让我举一个简单的例子。如果

ArrayList<String> strings = new ArrayList<String>();
ArrayList<Object> objects = strings;

有可能,如果有人打电话

objects.add(new Object());

会发生什么?因为 strings 只能容纳 Strings,所以 Java 不能 "put" 一个 Object 进入这个列表。但另一方面,如果您查看 objects 的声明,没有任何暗示,这不应该起作用。因此,Java 不允许在泛型 类 之间进行转换,即使泛型类型处于关系中。

但是泛型类型在运行时不存在。那么什么是喧嚣? ArrayList<String> 在运行时真的不应该是 ArrayList<Object> 吗?因此,所有这些都不重要吗? 嗯,不。由于您在编译时知道类型,因此可以使用某些契约。例如,当从 ArrayList<String> 中检索一个元素时,可以确定此检索到的对象具有 public char charAt(int) 方法(因为 String 具有此方法)。如果出于某种原因,此 ArrayList<String> 会 return 一个 Object 而不是 String,则无法调用 charAt(int) 方法。