11

以下两个签名相同吗?

public static <T> void work(Class<T> type, T instance);

public static <T, S extends T> void work(Class<T> type, S instance);
4

3 回答 3

11

不,这两个签名不一样。来自Java 语言规范,第 8 章

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

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

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

...

由于您的两个方法不共享相同数量的类型参数,因此签名也不相同。

在使用隐式类型参数调用方法的实际情况下,它们可能被视为可互换的。但这只是在源代码级别,绝不是在二进制级别。换句话说,如果你有一个类型参数版本的work()in classFoo并且它被 class 中的方法调用Bar,然后你切换到两个类型参数版本work()并重新编译Foo,你还需要重新编译Bar

编辑

@onepotato 问:

如果它们没有相同的签名,那么为什么当我将它们复制并粘贴到一个类中时,Eclipse 告诉我它们具有相同的方法签名?

两个签名相等和两个签名冲突(“覆盖等效”)之间存在差异。如果一个签名是另一个签名的子签名,则两个签名会发生冲突。这将在同一部分稍后解释:

如果 m1 是 m2 的子签名或 m2 是 m1 的子签名,则两个方法签名 m1 和 m2 是覆盖等效的。

在一个类中声明两个具有重写等效签名的方法是编译时错误。

方法 m1 的签名是方法 m2 签名的子签名,如果:

  • m2 与 m1 具有相同的签名,或
  • m1 的签名与 m2 签名的擦除(第 4.6 节)相同。
于 2013-07-30T05:20:04.053 回答
3

只需查看字节码,我们就可以看到它们没有:

为了第一:

// access flags 0x9
// signature <T:Ljava/lang/Object;>(Ljava/lang/Class<TT;>;TT;)V
// declaration: void work<T>(java.lang.Class<T>, T)
public static work(Ljava/lang/Class;Ljava/lang/Object;)V
 L0
  LINENUMBER 86 L0
  RETURN
 L1
  LOCALVARIABLE type Ljava/lang/Class; L0 L1 0
  // signature Ljava/lang/Class<TT;>;
  // declaration: java.lang.Class<T>
  LOCALVARIABLE instance Ljava/lang/Object; L0 L1 1
  // signature TT;
  // declaration: T
  MAXSTACK = 0
  MAXLOCALS = 2

对于第二个:

// access flags 0x9
// signature <T:Ljava/lang/Object;S:TT;>(Ljava/lang/Class<TT;>;TS;)V
// declaration: void work<T, ST>( extends java.lang.Class<T>, S)
public static work(Ljava/lang/Class;Ljava/lang/Object;)V
 L0
  LINENUMBER 86 L0
  RETURN
 L1
  LOCALVARIABLE type Ljava/lang/Class; L0 L1 0
  // signature Ljava/lang/Class<TT;>;
  // declaration: java.lang.Class<T>
  LOCALVARIABLE instance Ljava/lang/Object; L0 L1 1
  // signature TS;
  // declaration: S
  MAXSTACK = 0
  MAXLOCALS = 2
于 2013-07-30T05:27:07.970 回答
1

对于任何一组参数,如果T存在的有效选择

<T> void work(Class<T> type, T instance)

那么一个有效的选择T并且S存在于

<T, S extends T> void work(Class<T> type, S instance)

反之亦然。

所以从理论上讲,它们是等价的。但是,由于推断有限,可能会出现这样的情况,当没有给出类型参数时,一个会编译而另一个不会编译某些参数。在这种情况下,始终可以为未编译的情况显式指定一组有效的类型参数,以使其编译。

由于它们是等价的,API 应该总是更喜欢更简单的形式,即没有S.

于 2013-07-31T00:10:30.377 回答