2016-07-21 22 views
2

Ich verstehe völlig die Löschung von generischen und daher kann Java Überladung nur Basis auf generische nicht. Was aber, wenn wir den Lambda-Ausdruck berücksichtigen?Überlädt Java tatsächlich Methoden, die auf generischen basieren, wenn Lambda beteiligt ist?

Siehe den folgenden Fall.

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");} 

Das Ergebnis jeder Anruffunktion ist genau das, was ich ohne Kompilierung oder Laufzeitfehler zu erwarten. Und das ist der reine Teil des Ganzen: plötzlich überlädt die Funktion auf Basis generischer Typen.

Was passiert eigentlich hinter den Kulissen?

+0

Ich verstehe Ihre Frage nicht. Sie übergeben eine 'HashMap '. Warum sollte es eine Verwechslung mit der anderen Methode geben? –

+0

Dies dupliziert im Grunde https://stackoverflow.com/questions/21905169/java8-ambiguity-with-lambdas-and-overloaded-methods?rq=1. Siehe die akzeptierte Antwort. – JudgingNotJudging

+0

@SotiriosDelimanolis Weil Java nicht auf generischen Typ überladen wird. HashMap und HashMap ist nach dem Kompilieren gleich. – Custer

Antwort

0

Interessante Frage.

Der Compiler entscheidet zur Kompilierzeit, welcher Typ die Lambda-Funktion ist. Obwohl die Generika an diesem Punkt gelöscht werden, wird auch der Typ der Funktion an diesem Punkt festgelegt, dh sie weiß, welche Methode aufgerufen werden muss .

Meine Vermutung ist, dass es das tun kann, weil es immer noch die generische Information in diesem Stadium hat - d. H. Es ist der Compiler, der es dann los wird.

Wenn Sie an der Bytecode für die Klasse aussehen heißt es:

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

Also für die HashMap die Typisierung ist weg, aber für die Schnittstelle hat der Typ eingestellt.

+0

Also ist es wahr, dass wir diesen Trick verwenden können, um zu erzwingen, dass der Compiler auf dem generischen Typ überlädt? – Custer

+0

Ich denke schon, aber wenn Sie eine andere Schnittstelle haben müssen, die jede mögliche Variation repräsentiert, negiert es irgendwie jeden Vorteil, den Sie daraus ziehen könnten. – gus