2014-06-24 20 views
8

W języku Java, czy możemy przekazać nadklasę Obiekt do odwołania do podklasy?W języku java, czy możemy przekazać nadklasę Obiekt do odwołania do podklasy?

Wiem, że to dziwne pytanie/praktycznie nie jest opłacalne, , ale chcę zrozumieć logikę stojącą za tym Dlaczego nie jest dozwolone w Javie.

class Employee { 
    public void met1(){ 
     System.out.println("met1"); 
    } 
} 


class SalesPerson extends Employee 
{ 
    @Override 
    public void met1(){ 
    System.out.println("new met1"); 
    } 


    public void met2(){ 
     System.out.println("met2"); 
    } 

} 

public class ReferenceTest { 
    public static void main(String[] args) { 

     SalesPerson sales = new Employee(); // line 1 

     sales.met1(); // line 2 

     sales.met2(); // line 3 
    } 
} 

Co by się stało, gdyby Java mogła kompilować linię 1? Gdzie powstałby problem?

Wszelkie dane wejściowe/link są mile widziane.

+1

To nie ma sensu. Gdyby było to dozwolone, możesz mieć pola/metody, których oczekiwałbyś, że tam nie ma. Gdyby było to dozwolone, myślę, że projektanci języków mogli zostać zablokowani gdzieś, gdzie nie mogliby zadawać większych obrażeń. – awksp

+0

czego się spodziewać? – Mark

Odpowiedz

18

Jeśli pozwolono na kompilację oświadczenia SalesPerson sales = new Employee();, naruszałoby to zasady Polymorphism, która jest jedną z funkcji języka.

Ponadto, należy zapoznać się z tym robi kompilacji typ czas i typu Runtime myśli:

Typ kompilacji zmiennej jest typem jest zadeklarowana jako, natomiast runtime type to typ rzeczywistego obiektu, do którego wskazuje zmienna. Na przykład:

Employee sales = new SalesPerson(); 

typ kompilacji czas sales jest Employee oraz typ środowiska wykonawczego będzie SalesPerson. Typ kompilacji określa, które metody można wywołać, podczas gdy typ środowiska wykonawczego określa, co dzieje się podczas faktycznego połączenia.

Załóżmy przez chwilę, że to stwierdzenie było ważne:

SalesPerson sales = new Employee(); 

Jak powiedziałem, rodzaj kompilacji określa, które mogą być wywoływane metody, więc met2() byłby uprawniony do wywoływania. Tymczasem klasa Employee nie ma numeru met2(), więc faktyczne połączenie byłoby niemożliwe.

+0

Doskonała odpowiedź. – user2601010

+0

Co z pracownikami e = new SalesPerson(); e.met2(); Myślę, że to możliwe, ale jak? czas kompilacji nie ma metody met2(). Czy nie powinien on rzucać błędu? – RajSharma

+0

@RajSharma niedozwolone. spowoduje to błąd podczas kompilacji, ponieważ nie ma metody met2() w Employee – crazyStart

3

Jeśli dziedziczysz z klasy, zawsze specjalizujesz się w typowym zachowaniu super klasy.

W swoim przykładzie SalesPerson jest specjalnym Employee. Dziedziczy wszystkie zachowania od super klasy i może przesłonić zachowanie, aby je zmienić lub dodać nowe zachowanie.

Jeśli, tak jak jest to dozwolone, zainicjuj zmienną supertypu za pomocą instancji typu podrzędnego, takiej jak Employee e = new SalesPerson(), możesz użyć wszystkich typowych zachowań dla tej zmiennej.

Jeśli zamiast tego można było zrobić odwrotnie, w klasie może być kilku niezainicjowanych członków.

Bardzo często zdarza się to podczas korzystania z interfejsu API Java Collection, gdzie można na przykład używać wspólnej klasy List w operacjach takich jak iterowanie przez nią, ale podczas jej inicjowania używa się na przykład podkategorii ArrayList.

4

Nie. Nie ma sensu na to pozwalać.

Powodem jest to, że podklasy ogólnie definiują zachowanie dodatkowe. Jeśli można przypisać obiekt nadklasy do odwołania do podklasy, wystąpią problemy w czasie wykonywania podczas próby uzyskania dostępu do elementów klasy, które w rzeczywistości nie istnieją.

Na przykład, jeżeli zostały dopuszczone:

String s = new Object(); 

byłoby uruchomić w niektórych dość złych problemów. Co się stanie, jeśli spróbujesz wywołać metodę String? Czy środowisko uruchomieniowe ulegnie awarii? A może wykonano by operację no-op? Czy to powinno się skompilować?

Jeśli środowisko wykonawcze uległo awarii, można użyć sprawdzeń w czasie wykonywania, aby upewnić się, że otrzymane obiekty będą faktycznie zawierać żądane metody. Ale w zasadzie wprowadzasz gwarancje, że system typu Java już zapewnia podczas kompilacji. Tak naprawdę ta "funkcja" kosztowała cię tylko garść kodu sprawdzającego typ, którego nie powinieneś był pisać.

Jeśli zamiast nieistniejących metod wykonano operacje bez oportunistyczne, niezwykle trudno byłoby zapewnić, że programy będą działać tak, jak napisane, gdy członkowie, do których chcemy uzyskać dostęp, nie istnieją, ponieważ każde odwołanie może być naprawdę zgodne z Object pod adresem dowolny punkt. Może to być łatwe do opanowania, gdy pracujesz samodzielnie i kontrolujesz cały swój kod, ale gdy masz do czynienia z innym kodem, te gwarancje zasadniczo znikają.

Jeśli chcesz, aby kompilator wykonywał sprawdzanie, zakładając, że autorzy kompilatorów nie będą cię ścigać i rzucą ci surową rozmowę, to znów powrócisz do "normalnego" zachowania. Znowu, to po prostu dużo pracy dla zerowej korzyści.


Krótko mówiąc: Nie, to nie jest dozwolone, ponieważ sprawia, że ​​zerowy sens, aby to zrobić, a jeśli projektant język próbował pozwolić, że zostaną zamknięte, zanim będą mogły robić żadnych więcej szkody.