2013-03-20 22 views
5

Oto trzy klasy, które napisałem:Polimorfizm ze zmiennych instancji

public class Shape { 

    public int x = 0; 

    public void getArea() { 
     System.out.println("I don't know my area!"); 
    } 

    public String toString() { 
     return "I am a shape!"; 
    } 

    public int getX() { 
     return x; 
    } 
} 

public class Rectangle extends Shape { 

    public int x = 1; 

    public int getX() { 
     return x; 
    } 

    public void getArea() { 
     System.out.println("L*W"); 
    } 

    public String toString() { 
     return "I am a rectangle!"; 
    } 
} 

public class Tester { 

    public static void main(String[] args) { 
     Shape s = new Shape(); 
     Rectangle r = new Rectangle(); 

     System.out.println(r); 
     System.out.println(r.x + "\n"); 

     s = r; 
     System.out.println(s); 
     s.getArea(); 
     System.out.println(s.x); 
     System.out.println(s.getX()); 
    } 
} 

Wyjście z głównej metody klasy Tester jest:

 
I am a rectangle! 

1 

I am a rectangle! 

L*W 

0 

1 

Dlaczego s.x zwraca 0, a nie 1? Ponieważ nie jest bieżącą instancją zmiennej Rectangle i ta klasa ma zadeklarowaną tę samą instancję zmiennej, czy też zmienna w klasie Rectangle nie przesłania poprzedniej zmiennej publicznej x w klasie Shape tak jak robi to w getX() metoda w klasie prostokąta, zwracając 1?

Co więcej, nadrzędna klasa ma również dostęp do implementacji metod jej podklas tylko wtedy, gdy są one zadeklarowane również w tej klasie? Czy to dlatego, że kompilator zobaczy, że ta sama ilość metod z tym samym sygnaturą znajduje się w klasie "Shape" (z przesłoniętymi implementacjami Rectangle) i akceptuje je jako prawidłowe metody Shape?

Dzięki z góry,

+0

Dlaczego to instancja zmiennej publicznej !!? Nigdy nie powinieneś nigdy udostępniać publicznie zmiennej instancji !!! – DrinkJavaCodeJava

+0

To był test, aby zobaczyć, co się stanie. Doskonale zdaję sobie sprawę z enkapsulacji, jak robiłem wcześniej projekt MVC. – PragmaticProgrammer

Odpowiedz

13

Nie ma polimorfizmu dla pól w Javie. Istnieje jednak dziedziczenie. To, co udało Ci się skutecznie zrobić, to stworzyć dwa pola w klasie Rectangle o tej samej nazwie. Nazwy tej dziedzinie są skutecznie:

public class Rectangle { 
    public int Shape.x; 
    public int Rectangle.x; 
} 

Powyższe nie stanowią ważny Java, jej tylko ilustrację jak pola są scoped w swojej klasie

ciągu całego zakresu Klasa prostokątu, pole nadklasy o tej samej nazwie to ukryta. Dlatego w dowolnym momencie odwołujesz się do prostej nazwy x lub o nazwie o zakresie this.x w klasie, odnosząc się do pola zdefiniowanego w Rectangle. W rzeczywistości można uzyskać dostęp do pola nadklasy również o nazwie o zakresie super.x.

Teraz, spoza klasy, zasady, dla których dostęp do pola jest nieco inny. Zakres będzie określony przez typ czasu klasy, z której odwoływane jest pole. Tak w kodzie:

Shape s = new Shape(); 
Rectangle r = new Rectangle(); 

s = r; 
System.out.println(s.x); 

Wyjście jest 0 ponieważ typ kompilacji czas s jest Shape (nie Rectangle). Możesz zaobserwować zmianę tego zachowania, gdy to zrobisz:

Shape s = new Shape(); 
Rectangle r = new Rectangle(); 

s = r; 
System.out.println(((Rectangle)s).x); 

Presto! Twoje dane wyjściowe są teraz 1, ponieważ kompilator widzi, że masz dostęp do pola o wartości Rectangle.

skondensować zasady widoczności:

Możesz przeczytać więcej o zmiennej instancji ukryciu w JLS, Section 8.3.3.2

+0

Dziękuję teraz rozumiem! Więc czy metody używają implementacji prostokątów, tak jak powiedziałem przy użyciu s.getArea()? Wiem, że wydaje się, ale co tak naprawdę dzieje się podczas kompilacji? Dzięki – PragmaticProgrammer

+0

@PragmaticProgrammer - zasady dla metod są różne, po pierwsze, mogą zostać przesłonięte. Pamiętasz, jak wspomniałem, że dla zmiennych ukrytych, rozdzielczość jest wykonywana w czasie kompilacji? Cóż, aby przesłonić metody, rozdzielczość jest wykonywana w czasie wykonywania. Tak więc, jeśli zrobiłeś 'Shape s = new Rectangle(); s.getArea(); 'wywołana metoda dotyczy podklasy' Rectangle', a nie klasy superklasy 'Shape'. – Perception

0

podklasy dziedziczą tylko zmienne i metod nadklasy, a nie na odwrót. Aby uzyskać x równe 1, trzeba nazwać prostokątem, a nie kształtem. Bez tego, co robił inny facet przy rzucaniu, którego należy unikać w rzeczywistym programowaniu. Poza tym nigdy nie powinieneś używać publicznych instancji zmiennych! Jeśli chcesz, aby zmienne były upublicznione, przynajmniej uczyń je statycznymi lub stałymi.