2017-02-27 15 views
8

Jestem trochę zmieszany z różnymi zachowaniami anonimowej klasy i wyrażeniem lambda.Wartość "this" w anonimowej klasie w stosunku do wyrażenia lambda

Kiedy używam wyrażenia lambda:

//Test.java 

Runnable r1 =() -> System.out.println(this); 
Runnable r2 =() -> System.out.println(toString()); 

@Override 
public String toString() { 
    return "Hello World!"; 
} 

// in main method 
new Test().r1.run(); 
new Test().r2.run(); 
Output : Hello World! 
     Hello World! 

Podczas korzystania anonimową klasę:

Runnable r1 = new Runnable() { 
    @Override 
    public void run() { 
     System.out.println(this); 
    } 
}; 

Runnable r2 = new Runnable() { 
    @Override 
    public void run() { 
     System.out.println(toString()); 
    } 
}; 

@Override 
public String toString() { 
    return "Hello World!"; 
} 

// in main method 
new Test().r1.run(); 
new Test().r2.run(); 
Output : [email protected] 
     [email protected] 

Czy ktoś mógłby wyjaśnić różne zachowanie?

Odpowiedz

10

W wyrażeniu lambda, this jest leksykalnie związany z otaczającą klasą, podczas gdy w anonimowej klasie this jest leksykalnie związany z anonimową klasą.

Java Language Specification opisuje ten problem w 15.27.2:

przeciwieństwie kodem zawartym w deklaracji anonimowych klasy, znaczenie imion i this i super słowa kluczowe występujące w organizmie lambda wraz z dostępnością odwoływać deklaracje są takie same jak w otaczającym kontekście (z wyjątkiem tego, że parametry lambda wprowadzają nowe nazwy).

Przejrzystość this (zarówno jawny i ukryte) w korpusie wyrażenia lambda - to znaczy, leczenie to samo co w otaczającym kontekście - pozwala na większą elastyczność w realizacji, i zapobiega znaczenie absolutnego nazwami w ciało jest zależne od rozdzielczości przeciążenia.

Praktycznie rzecz biorąc, jest to niezwykłe wyrażenie lambda trzeba mówić o sobie (albo nazywać się rekurencyjnie lub powołać się na swoje inne metody), gdy jest bardziej powszechne chce używać nazwy odnoszą się do rzeczy w klasie otaczającej, która w przeciwnym razie byłaby zacieniona (this, toString()). Jeśli konieczne jest, aby wyrażenie lambda odnosiło się do siebie (tak jak przez this), zamiast tego należy użyć odwołania do metody lub anonimowej klasy wewnętrznej.

W celu odwoływać this otaczającej klasy od wewnątrz anonimowej klasy, trzeba będzie użyć qualified this.

+0

Dzięki za odpowiedź :), ale co jest leksykalnie związane? –

+2

@MehrajMalik Oznacza to, że są one powiązane w czasie kompilacji w zależności od kontekstu, w jakim zostały znalezione. – 4castle

+3

To nie tylko wpływa na 'ten' i' super'. Wewnątrz anonimowej klasy wewnętrznej mogą istnieć dziedziczone elementy (nie tylko 'toString()'), podczas gdy wyrażenie lambda niczego nie dziedziczy po interfejsie funkcjonalnym. – Holger