实现两个方法签名相同但返回类型不同的接口

Luk*_*lor 3 java oop inheritance interface

假设我有两个接口:

public interface InterfaceA {
 public int getStuff();

}

public interface InterfaceB {
 public String getStuff();

}
Run Code Online (Sandbox Code Playgroud)

现在我有一个实现这两个接口的类:

public class Testing implements InterfaceA, InterfaceB{
 public String getStuff() {
   return "one";
 }

}
Run Code Online (Sandbox Code Playgroud)

我的问题是,这会编译吗?如果它确实编译了,它会运行吗?

编辑:

我确实在我的电脑上试过这个,发现它编译并运行了,但是当调用 getStuff() 时,程序以

未解决的编译问题

任何想法 Java 在较低级别上做什么?

Tob*_*ias 5

这会编译吗?如果它确实编译了,它会运行吗?

您可能会感到惊讶:它不会编译,但如果编译了,它会运行。

Java 编译器要求您实现在您在类上声明的接口中声明的所有方法。在你的情况,你需要实现两个 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
Run Code Online (Sandbox Code Playgroud)

我们声明了一个类Testing,它声明了两个具有相同名称和参数的方法,唯一的区别是返回类型。它实现了这两个接口,并有一个public static void main(String[] args)方法来调用这两个方法(getStuff()getStuff())并显示结果。而且这个程序确实有效,虚拟机没有抱怨任何东西。

为什么有效?的JVM规范定义了描述这样的方法的:

MethodDescriptor:
    ( ParameterDescriptor* ) ReturnDescriptor
Run Code Online (Sandbox Code Playgroud)

该描述符用于(除了类和方法名称之外)在运行时解析方法。因为它包含ReturnDescriptor,所以可以有多个同名的方法。

编译器呢?编译器不使用它们的描述符来识别方法,而是使用它们的签名。在Java语言规范包含此:

如果两个方法具有相同的名称和参数类型,则它们具有相同的签名。

如果以下所有条件都成立,则两个方法或构造函数声明 M 和 N 具有相同的参数类型:

  • 它们具有相同数量的形式参数(可能为零)

  • 它们具有相同数量的类型参数(可能为零)

  • 设 A1, ..., An 为 M 的类型参数, B1, ..., Bn 为 N 的类型参数。 将 N 类型中每次出现的 Bi 重命名为 Ai 后,对应类型变量的边界为相同,且 M 和 N 的形参类型相同。

因此,在源代码中无法通过方法的返回类型来区分方法,并且编译器禁止声明仅在返回类型上不同的方法。