我完全理解泛型的擦除,因此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");}
每个函数调用的结果正是我所期望的,没有任何编译或运行时错误。这就是整个事情的疲惫部分:突然,函数基于泛型类型进行重载。
那么幕后实际发生了什么?
答案 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,输入已经消失,但是对于接口,已经设置了类型。