当前位置: 首页 > 面试题库 >

Java中的擦除和重载类型:为什么这样做有效?

尉迟轶
2023-03-14
问题内容

我有以下代码

public class Pair< T, U > {
    public T first;
    public U second;
}
public class Test {
    public int method( Pair< Integer, Integer > pair ) {
        return 0;
    }
    public double method( Pair< Double, Double > pair ) {
        return 1.0;
    }
}

实际上,它可以像人们期望的那样进行编译和工作。但是,如果将返回类型设为相同,则不会编译,因为预期的“名称冲突:method(Pair)和method(Pair)具有相同的擦除”

鉴于返回类型不是方法签名的一部分,这种重载怎么可能?


问题答案:

考虑以下4种方法

           Java code                        bytecode

m1:    Byte f(List<Byte> list)           f List -> Byte
m2:    Long f(List<Byte> list)           f List -> Long
m3:    Byte f(List<Long> list)           f List -> Byte
m4:    Long f(List<Long> list)           f List -> Long

根据当前的Java语言规范,

  • m1和m2无法共存,m3和m4也不能共存。因为它们具有相同的参数类型。

  • M1和M3可以共存,M1和M4也可以共存。因为它们具有不同的参数类型。

但是javac 6仅允许m1 + m4,不允许m1 + m3。这与方法的字节码表示有关,其中包括返回类型。因此,m1 + m4可以,但m1 + m3则不行。

这是Java和JVM规范无法相互对照的一个附加条件。javac没有“正确”的方法。

好消息是,过载是虚荣,而不是必要。对于这些方法,我们总是可以使用不同的,更具描述性的和不同的名称。



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

  • 下面的代码没有在OpenjDK 11上编译。在我看来,B中的test1应该覆盖A中的test1,因为: 方法有相同的名称。 这些方法具有相同的参数列表。 这些方法具有相同的可见性。 这些方法实际上不会抛出可能不兼容的检查异常。 它们的返回类型是协变的。 我使用了一个反编译器,分别对每个类进行反编译。编译后的代码实际上像我期望的那样工作。它用数字代替U扩展数字,用整数代替T扩展整数,以此类推。但当我

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

  • 可能重复: 面试:我们可以实例化抽象类吗? 我有一个定义了所有方法的抽象类(即其中没有包含任何抽象方法),如下所示: 还有一个JUnit测试类: 和内部类有关系吗?

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

  • 问题内容: 到目前为止,我对Java Generics的理解显然是错误的,即Type Erasure删除了所有类型信息,从而在运行时几乎没有剩余。最近,我偶然发现了一个代码片段,不得不问自己:这种破解是如何工作的?简化后,它表示为: 和 执行Main Class结果。 我们在这里看到的是,T的类型信息在运行时也可用,这与我的最初理解相矛盾。 所以我的问题是:为什么编译器会保留此?这对于某些内部JV