当lambda涉及时,java实际上是基于泛型的重载方法吗?

时间:2016-07-21 17:28:46

标签: java generics lambda overloading

我完全理解泛型的擦除,因此java不能仅基于泛型进行重载。但是如果我们考虑lambda表达式怎么办?

请参阅以下案例。

interface base{
    void test();
}
// compiler cant distinguish these two interfaces by lambda expression we provided 
interface Foo extends base{}
interface Boo extends base{}

public static void main(String[] args) throws ClassNotFoundException {
    HashMap<String,Long> set = new HashMap<>();
    // this is valid, since type Foo is explicitly given out
    t1(set,new Foo(){
        @Override
        public void test(){
        }
    }); // "Long"

    // using lambda expression make the second argument indistinguishable, 
    //so the overloading can only depend on the first argument which is a
    //Hashmap with generic type.
    // but the compiler still managed to work this out
    t1(set,()->{});// "Long"

    HashMap<String,Integer> set2 = new HashMap<>();
    t1(set2,()->{});// "Integer"
}
public static void t1(HashMap<String,Long> set,Foo foo){System.out.println("Long");}
public static void t1(HashMap<String,Integer> set,Boo boo){System.out.println("Integer");}

每个函数调用的结果正是我所期望的,没有任何编译或运行时错误。这就是整个事情的疲惫部分:突然,函数基于泛型类型进行重载。

那么幕后实际发生了什么?

1 个答案:

答案 0 :(得分:0)

有趣的问题。

编译器在编译时决定lambda函数是什么类型的,所以即使泛型在那一点被擦除,函数的类型也会在那一点设置,这意味着它知道必须调用什么方法。

我的猜测是它可以做到这一点,因为它在那个阶段仍然具有通用信息 - 即编译器然后摆脱它。

如果你查看该类的字节码,它会说:

16: invokestatic  #25                 // Method t1:
     (Ljava/util/HashMap;LTest$Foo;)V
25: invokestatic  #25  // Method t1:   
    (Ljava/util/HashMap;LTest$Foo;)V

因此,对于HashMap,输入已经消失,但是对于接口,已经设置了类型。