java泛型边界类型

时间:2013-07-30 04:48:56

标签: java generics

以下两个签名是否相同?

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

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

3 个答案:

答案 0 :(得分:11)

不,两个签名不一样。来自Java Language Spec, Chapter 8

  

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

     

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

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

...

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

在使用隐式类型参数调用方法的实际情况中,它们可能被视为可互换。但这只是在源级别,而不是在二进制级别。换句话说,如果您在类work()中拥有Foo的单类型参数版本,并且它已被类Bar中的方法调用,那么您切换到了类型参数版本work()并重新编译Foo,您还需要重新编译Bar

修改

@onepotato问道:

  

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

两个签名相等和两个签名冲突(“覆盖等效”)之间存在差异。如果一个是另一个的子签名,则两个签名冲突。稍后将在同一部分对此进行说明:

  

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

     

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

     

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

     
      
  • m2与m1具有相同的签名,或
  •   
  • m1的签名与m2签名的删除(§4.6)相同。
  •   

答案 1 :(得分: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

答案 2 :(得分:1)

对于任何参数集,如果

存在有效的T选项

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

然后

存在TS的有效选择

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

反之亦然。

所以从理论的角度来看,它们是等价的。但是,由于推理有限,可能会出现这样的情况:当没有给出类型参数时,将会编译而另一个不会针对某些参数进行编译。在这种情况下,总是可以为不编译的情况显式指定一组有效的类型参数,以使其编译。

因为它们是等价的,所以API应该总是更喜欢更简单的形式,即没有S