2013-06-06 13 views
8

Proszę sprawdzić kod Java poniżej:Jak używać zmiennych składowych z interfejsami i anonimowych implementacje

public class Test 
{ 
    public static void main(String arg[]) throws Throwable 
    { 
     Test t = new Test(); 
     System.out.println(t.meth().s);   //OP: Old value 
     System.out.println(t.meth().getVal()); //OP: String Implementation 
    } 
    private TestInter meth() 
    { 
    return new TestInter() 
    { 
     public String s = "String Implementation"; 
     public String getVal() 
     { 
     return this.s; 
     } 
    }; 
    } 
} 
interface TestInter 
{ 
    String s = "Old value"; 
    String getVal(); 
} 

Jak widać ja stworzyliśmy interfejs anonimowo. Kiedy uzyskuję bezpośredni dostęp do zmiennej interfejsu, wyświetli się "Stara wartość".

t.meth(). S => "Stare wartość"

dostępu do niego przez GETVAL() Metoda zwraca odpowiednie wartości,

t.meth(). GETVAL() => „String Implementacja "

Nie rozumiem, jak działa ten kod, czy ktoś może mi to wyjaśnić?

Odpowiedz

7

s zmienne zadeklarowane w interfejsie jest całkowicie oddzielone z s zmiennej zadeklarowanej już w swojej anonimowej klasy wewnętrznej.

Zmienne interfejsowe są tak naprawdę zaprojektowane, aby być stałymi - nie są częścią interfejsu API, który musi zapewnić każda implementacja. W szczególności są one domyślnie statyczne i ostateczne.

Z JLS section 9.3:

Każda deklaracja pola w organizmie interfejs jest domyślnie publiczne, statyczne i końcowe. Dozwolone jest redundancyjne określenie dowolnego lub wszystkich tych modyfikatorów dla takich pól.

Fakt, że masz dostęp do pola poprzez przykład implementacja jest nieistotne - ten kod:

System.out.println(t.meth().s); 

to skutecznie:

t.meth(); 
System.out.println(TestInter.s); 

Gorąco zachęcamy do unikać zmienne w interfejsach z wyjątkiem dla prawdziwych stałych ... a nawet wtedy, tylko tam, gdzie ma to sens. Nie jest jasne, co próbujesz osiągnąć, ale deklarowanie pola w interfejsie nie jest dobrym rozwiązaniem IMO.

+0

Można zniechęcić do używania * lub * polecania, aby uniknąć zmiennych w interfejsach, prawda? – Fildor

+0

@Fildor: Naprawiono, dzięki. –

+0

@JonSkeet, ale mimo tego, że rozszerza normalną klasę zamiast interfejsu, otrzymuje takie same wyniki. Testowałem to. czy mam rację, właśnie to sformułowałem w mojej odpowiedzi ... proszę, popraw mnie, jeśli się mylę ... dzięki :) – pinkpanther

3

Nie ma to jak variable-overriding jak method overriding w języku Java. Nazwij nowy typ dla subclass, wtedy uzyskasz "String Implementation", gdy uzyskasz dostęp przez typ odwołania do podklasy.

Uprawnienie dostępu protected oznacza tylko, że możemy uzyskać dostęp do zmiennej w podklasie, ale nie można jej zastąpić.

Nawet jeśli używasz zwykłego class zamiast interface, to nie zadziała. Kiedy polecisz za pomocą super typ klasy, można dostać tylko instance zmienne z super typu i tak dalej .... Ten przykład ilustruje pierwszy przypadek: Przykład:

public class Tester 
{ 
    public static void main(String arg[]) throws Throwable 
    { 
     Tester t = new Tester(); 
     System.out.println(t.meth().s); // it prints "Old value" because your type is TestInter   
    } 
    private TestInter meth() 
    { 
    return new TestInter() 
    { 
     protected String s = "String Implementation"; 

    }; 
    } 
} 
class TestInter 
{ 
    protected String s = "Old value"; 

} 

Ten przykład ilustruje drugi przypadek: drukuje "String Implementation"

public class Tester 
{ 
    public static void main(String arg[]) throws Throwable 
    { 
     Tester t = new Tester(); 
     System.out.println(t.meth().s);   
    } 
    private SubTestInter meth() 
    { 
    return new SubTestInter(); 
    } 
} 
class SubTestInter extends TestInter{ 
     protected String s = "String Implementation"; 
} 
class TestInter 
{ 
    protected String s = "Old value"; 

} 
1
When i access a interface variable directly 

mieć odniesienie do typu interfejsu, dlatego odnosi interfejs bezpośrednio i masz „starą wartość”

Accessing getVal() method, showing proper values 

Po wywołaniu metody GETVAL(), które odnoszą się do faktycznej realizacji tej metody i dlatego GETVAL faktycznej realizacji jest tzw. Oznacza to bieżące wystąpienie z następujących wartości:

public String s = "String Implementation"; 
1

Pola zadeklarowane w interfejsie są stałymi.

Zatem pisząc

interface TestInter 
{ 
    String s = "Old value"; 
    String getVal(); 
} 

Jesteś deklarowania stałej s. Dlatego t.meth().s drukuje Old value

t.meth().getVal() drukuje zawartość pola s swojej anonimowej klasy.

Powiązane problemy