当前位置: 首页 > 知识库问答 >
问题:

Java类型擦除和多个边界

公孙阳羽
2023-03-14

我知道在Java泛型中,当使用具有多个边界的类型参数时,编译器会将类型信息擦除到“最左边的边界”(即列表中的第一个类/枚举或接口)。那么为什么以下代码编译没有问题呢?

public class Generic<T extends Object & Appendable & AutoCloseable> {

  T t;

  T method() throws Exception {
    t.close();
    char c='\u0000';
    t.append(c);
    return t;
  }

  public <T> T method2(T t) {
    return t;
  }  

}

类型参数不应该被视为对象吗??(因此不允许我调用close()或append())??

共有3个答案

微生自怡
2023-03-14

这是你的反汇编代码。变量t是对象类型。指令checkcast在调用接口方法之前生成。如果t的值未实现接口,则将抛出ClassCastException。

Compiled from "Generic.java"
public class Generic<T extends java.lang.Appendable & java.lang.AutoCloseable> {
  T t;

  public Generic();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  T method() throws java.lang.Exception;
    Code:
       0: aload_0
       1: getfield      #2                  // Field t:Ljava/lang/Object;
       4: checkcast     #3                  // class java/lang/AutoCloseable
       7: invokeinterface #4,  1            // InterfaceMethod java/lang/AutoCloseable.close:()V
      12: iconst_0
      13: istore_1
      14: aload_0
      15: getfield      #2                  // Field t:Ljava/lang/Object;
      18: checkcast     #5                  // class java/lang/Appendable
      21: iload_1
      22: invokeinterface #6,  2            // InterfaceMethod java/lang/Appendable.append:(C)Ljava/lang/Appendable;
      27: pop
      28: aload_0
      29: getfield      #2                  // Field t:Ljava/lang/Object;
      32: areturn

  public <T> T method2(T);
    Code:
       0: aload_1
       1: areturn
}
湛财
2023-03-14

你的案子有多重界限。

具有多个边界的类型变量是边界中列出的所有类型的子类型。如果其中一个边界是类,则必须首先指定它。

因此,调用包含在接口AutoCloseable中的方法off()和包含在接口Appendable中的append()在语法上是合法的。

胡鸿远
2023-03-14

你应该在这里阅读有关桥接方法的内容

编译扩展参数化类或实现参数化接口的类或接口时,编译器可能需要创建称为桥接方法的合成方法,作为类型擦除过程的一部分。您通常不需要担心桥接方法,但如果堆栈跟踪中出现桥接方法,您可能会感到困惑。

 类似资料:
  • OracleDoc说泛型是在java中使用调用类型擦除的技术实现的,这就是它的工作原理。 如果类型参数是无界的,则用其边界或对象替换泛型类型中的所有类型参数。因此,生成的字节码只包含普通类、接口和方法 所以,如果我有一个通用类说容器如下: 通过类型擦除处理后,它的等效类将如下所示: 如果这里有错误,请纠正我 类似地,如果a修改上述类,如下所示 这不会相当于??? 如果这是真的,那么我也应该有这样的

  • 问题内容: 我以为Java擦除会在编译时消除泛型类型,但是当我自己对其进行测试时,我意识到在Bytecode中有一些有关泛型类型的信息。 这是我的测试: 我写了2节课: 和 我编译了两个类,并在通用类的某个地方看到了这一行 在非泛型类中: 所以很明显我在字节码中有通用信息,那么这个擦除的东西是什么? 问题答案: 一些通用类型信息存储在属性中。请参阅JLS 4.8 和4.6以及JVM规范4.3.4。

  • 问题内容: 类型擦除应该擦除所有泛型信息…如果是这种情况,那么像GSON这样的库如何使用泛型来确定反序列化为哪种类型? 例如 这将反序列 化为 将反序列化为 因此以某种方式在运行时使用通用信息。 问题答案: 类型擦除不会擦除所有类型信息。它不会从类,字段,返回类型和参数定义中将其删除。保留以下示例中的类型信息: 这是可以通过反射实现的。您可以检查给定的是否是该类,将其强制转换为该类并获取类型信息。

  • 问题内容: 有没有一种方法可以避免类型擦除并获得对类型参数的访问? 我需要了解并使用它来做事。是否可以,如果可以,如何在 不 将类传入构造函数或参数之外的任何地方的 情况下 完成操作? 编辑: 这个问题的主要目的是找出是否有 任何实用的方法 来消除类型擦除。 问题答案: 实际上, 没有 类型擦除的实用方法,因为您不能要求运行时无法访问的内容。当然,假设您同意为实现接口的每个枚举子类化通用类是一个实

  • 我有一个这样定义的方法: 我的单元测试我错误地这样测试它: 这应该会产生编译时错误(当我尝试使用javac编译它时,它会产生编译时错误),但eclipse允许它编译。 我真的不明白为什么eclipse允许这段代码编译,有人能提供一些信息吗,为什么这会在eclipse中编译? eclipse版本是:面向Web开发人员的eclipse Java EE IDE。版本:Luna Service Relea

  • 泛型用于在编译时进行更严格的类型检查并提供通用编程。 为了实现通用行为,java编译器应用类型擦除。 类型擦除是编译器用实际的类或桥接方法替换泛型参数的过程。 在类型擦除中,编译器确保不会创建额外的类,也不会有运行时开销。 键入Erasure规则 如果使用有界类型参数,则使用其绑定替换泛型类型中的类型参数。 如果使用无界类型参数,则使用Object替换泛型类型参数。 插入类型转换以保持类型安全。