这会编译吗?如果它编译了,它会运行吗?
您可能会感到惊讶:它不会编译,但如果可以,它会运行。
Java 编译器要求您实现在类上声明的接口中声明的所有方法。在您的情况下,您需要实现 both public int getStuff(); 和 public String getStuff();。如果不这样做,编译器将显示错误:
测试不是抽象的,不会覆盖 InterfaceA 中的抽象方法 getStuff()
测试中的 getStuff() 无法在 InterfaceA 中实现 getStuff()
现在,对于 Java 虚拟机,在您的类中同时包含这两种方法会非常好。但是,Java 编译器不允许这样做:
方法 getStuff() 已在类 Testing 中定义
因此您的代码不会以一种或另一种方式编译。
您知道 Java 在较低级别上做了什么吗?
让我们回到 JVM 本身并做一些邪恶的事情。看看这个jasmin 程序:
.class public Testing
.super java/lang/Object
.implements InterfaceA
.implements InterfaceB
.method public static getStuff()I
ldc 666
ireturn
.end method
.method public static getStuff()Ljava/lang/String;
ldc "Evil stuff"
areturn
.end method
.method public static main([Ljava/lang/String;)V
.limit stack 10
getstatic java/lang/System/out Ljava/io/PrintStream;
dup
invokestatic Testing/getStuff()I
invokevirtual java/io/PrintStream/println(I)V
invokestatic Testing/getStuff()Ljava/lang/String;
invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V
return
.end method
我们声明一个类Testing,它声明了两个具有相同名称和参数的方法,唯一的区别是返回类型。它实现了这两个接口并有一个public static void main(String[] args) 方法,该方法调用这两个方法(getStuff() 和getStuff())并显示结果。而且这个程序确实可以运行,虚拟机也不会抱怨什么。
为什么有效? JVM specification 定义了这样一个方法的描述符:
MethodDescriptor:
( ParameterDescriptor* ) ReturnDescriptor
此描述符用于(除了类和方法名称)在运行时解析方法。因为它包含ReturnDescriptor,所以可以有多个同名的方法。
编译器呢?编译器不使用它们的描述符 来识别方法,而是使用它们的签名。 Java language specification 包含以下内容:
两个方法具有相同的签名,如果它们具有相同的名称和
参数类型。
两个方法或构造函数声明 M 和 N 具有相同的参数
如果满足以下所有条件,则类型:
它们具有相同数量的形参(可能为零)
它们具有相同数量的类型参数(可能为零)
令 A1, ..., An 为 M 的类型参数,令 B1, ..., Bn 为 N 的类型参数。将 N 的类型中出现的 Bi 重命名为 Ai 后,对应类型变量的边界相同,M和N的形参类型相同。
因此,方法在源代码中无法通过返回类型来区分,编译器禁止声明仅返回类型不同的方法。