【问题标题】:Generics Inheritance common misunderstanding [duplicate]泛型继承常见误解[重复]
【发布时间】:2020-06-18 00:10:20
【问题描述】:

我是 Generic in Java 的初学者,我正在学习关于这个概念的课程。本课程的讲师这样解释这些代码:

代码:

public class Instructor extends User { // --- }

--

public class Utils {
    public static void printUsers(GenericList<User> users){
        // ---
    }
}

--

public class Test {
    public static void main(String[] args) {

         var users = new GenericList<Instructor>();

         Utils.printUsers(instructors);
    }
}

他的解释:

在 main 方法中,我们得到编译错误,因为 GenericList Instructor 不是 User 的 GenericList 的子类型。我的意思是GenericList&lt;Instructor&gt; 不会扩展和继承GenericList&lt;User&gt;。

这是为什么呢?我们查看了这个 GenericList 的字节码表示 班级。正如我之前向您展示的那样,这个 GenericList 在内部维护了一个 无论我们作为类型参数传递什么,Object 的列表。

无论我们通过User Class 还是Instructor Class,我们只有一个 在我们的项目中单个GenericList,并且此类不是 本身。这就是为什么 Instructor 的 GenericList 不是 User 的 GenericList 的子类型。因为我们正在处理一个单一的 类。

现在; 我完全糊涂了。非常非常困惑!

  1. 为什么他说我们只有一个班级? GenericList&lt;Instructor&gt; 和 GenericList&lt;User&gt; 是两个类,尽管它们具有相同的字节码。 (因为他们都维护对象列表,编译器会将每个T 替换为Object)

  2. 如果我们的项目中只有一个 GenericList 并且这个类不是它自己的子类型,那么 GenericList&lt;Instructor&gt;的实例和GenericList&lt;User&gt;的实例没有区别,它们都属于同一个类。

为什么我会得到这样的结果?因为根据老师的说法,我们只有一个类,那么为什么printUsers 方法不接受 GenericList 的实例作为参数?

最后,我对这一段一无所知:

无论我们通过User Class 还是Instructor Class,我们只有一个 在我们的项目中单个 GenericList 并且此类不是 本身。这就是为什么 Instructor 的 GenericList 不是 User 的 GenericList 的子类型。因为我们正在处理一个单一的 类。

谁能帮我理解这些解释?谢谢。

【问题讨论】:

  • GenericList&lt;T&gt; 类型在 T 类型中是泛型的,而不是在一组类型中。例如,如果您定义了GenericList&lt;? extends T&gt;,那么该代码将起作用。
  • 检查this。
  • 泛型类是同一个类;你没有两个班级。您有两个对泛型类的引用及其相关的编译时类型信息。而且,正如您所指出的,该类型信息在运行时不存在(类型擦除)。 docs.oracle.com/javase/tutorial/java/generics/erasure.html
  • @DaveNewton 在此链接中,他假设为两个类别:dzone.com/articles/how-do-generic-subtypes-work。他错了吗?
  • @MehSar 我会说他不精确,而且编译时间和运行时间是有区别的。它是具有不同类型(在编译时)的同一个类(这是泛型的重点)。

标签: java generics inheritance


【解决方案1】:

GenericList 类是单个类是正确的。泛型是一种编译类型安全,但它们会被编译器删除,因此它们在运行时不可用1。

但是,教练说这是GenericList&lt;User&gt;不是GenericList&lt;Instructor&gt;的原因,至少是有问题的2。

Dog 是 Animal,但 List&lt;Dog&gt; 不是 List&lt;Animal&gt;。 泛型是不变的。但是,如果没有,从技术上讲就没有问题。他们本可以为编译器提供一个类型系统,允许使用泛型类型T 的任何子类型来代替T 本身。然后仍然可以应用类型擦除。

另一方面,这是一个设计决定。 Jon Skeet points out an important reason to why generics are invariant.


为了让它工作,修改printUsers的方法签名:

public static <T extends User> void printUsers(GenericList<T> users) {

或者,因为您并不真正关心 User 的特定子类型 GenericList 包含,只是

public static void printUsers(GenericList<? extends User> users) {

1 导致泛型被删除的原因之一是,如果它们没有被删除,那意味着它们将被要求修改类文件的字节码结构,破坏 向后兼容 与以前的 Java 版本。

2 或者更强,我敢说它不准确。
• 由于类型擦除,GenericList 是一类(而不是二类)。
• 由于通用不变性,GenericList&lt;User&gt; 不是GenericList&lt;Instructor&gt;。
这是两个不同概念的两个不同原因。

【讨论】:

  • 这是两个独立的东西,但它们不是两个独立的类?
  • GenericList 是一个单一的类。尖括号之间的类型是类型参数,但类名仍然是GenericList。
猜你喜欢
  • 2011-08-17
  • 1970-01-01
  • 1970-01-01
  • 2011-08-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多