What is the difference between Java vararg with direct type vs wildcard generic via extends?

gavenkoa :

How do following 2 Java method declarations differ:

public <S extends Item> void withExtra1(S... extra) {
    Collections.addAll(pool, extra);
}

and:

public void withExtra2(Item... extra) {
    Collections.addAll(pool, extra);
}
andresp :

The Java spec says

A Java compiler must output generic signature information for any class, interface, constructor or member whose generic signature in the Java programming language would include references to type variables or parameterized types.

If you check the bytecode you can see the method with generics has a different signature:

  public <S extends Item> void withExtra1(S...);
    descriptor: ([LItem;)V
    flags: (0x0081) ACC_PUBLIC, ACC_VARARGS
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: getfield      #2                  // Field pool:Ljava/util/List;
         4: aload_1
         5: invokestatic  #3                  // Method java/util/Collections.addAll:(Ljava/util/Collection;[Ljava/lang/Object;)Z
         8: pop
         9: return
      LineNumberTable:
        line 9: 0
        line 10: 9
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      10     0  this   LItem;
            0      10     1 extra   [LItem;
      LocalVariableTypeTable:
        Start  Length  Slot  Name   Signature
            0      10     1 extra   [TS;
    Signature: #23                          // <S:LItem;>([TS;)V


  public void withExtra2(Item...);
    descriptor: ([LItem;)V
    flags: (0x0081) ACC_PUBLIC, ACC_VARARGS
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: getfield      #2                  // Field pool:Ljava/util/List;
         4: aload_1
         5: invokestatic  #3                  // Method java/util/Collections.addAll:(Ljava/util/Collection;[Ljava/lang/Object;)Z
         8: pop
         9: return
      LineNumberTable:
        line 13: 0
        line 14: 9
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      10     0  this   LItem;
            0      10     1 extra   [LItem;

#23 in the constant pool is #23 = Utf8 <S:LItem;>([TS;)V

You can access this information at runtime using reflection:

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class Item {

    List<Item> pool;

    public static void main(String[] args) {
        for (var m : Item.class.getMethods())
            System.out.println(m.getName() + " " +
                    Arrays.toString(m.getGenericParameterTypes()));
    }


    public <S extends Item> void withExtra1(S... extra) {
        Collections.addAll(pool, extra);
    }

    public void withExtra2(Item... extra) {
        Collections.addAll(pool, extra);
    }

}

stdout:

main [class [Ljava.lang.String;]
withExtra1 [S[]]
withExtra2 [class [LItem;]
wait [long]
wait [long, int]
wait []
equals [class java.lang.Object]
toString []
hashCode []
getClass []
notify []
notifyAll []

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=11942&siteId=1