JavaRush /Blog Java /Random-PL /Rozszerzanie i kurczenie się typów referencyjnych

Rozszerzanie i kurczenie się typów referencyjnych

Opublikowano w grupie Random-PL
Cześć! W jednym z poprzednich wykładów omawialiśmy rzutowanie typów pierwotnych. Przypomnijmy krótko, o czym rozmawialiśmy. Rozszerzanie i kurczenie się typów referencyjnych - 1Typy pierwotne (w tym przypadku numeryczne) reprezentowaliśmy jako lalki zagnieżdżające się w zależności od ilości zajmowanej przez nie pamięci. Jak pamiętacie, umieszczenie mniejszej lalki gniazdowej w większej będzie proste zarówno w prawdziwym życiu, jak i w programowaniu w Javie.
public class Main {
   public static void main(String[] args) {
        short smallNumber = 100;
        int bigNumber =  smallNumber;
        System.out.println(bigNumber);
   }
}
To jest przykład automatycznej konwersji lub rozszerzenia . Dzieje się to samo, więc nie ma potrzeby pisania dodatkowego kodu. Ostatecznie nie robimy nic niezwykłego: po prostu wkładamy mniejszą lalkę lęgową do większej lalki lęgowej. Co innego, jeśli spróbujemy zrobić odwrotnie i włożyć dużą lalkę matrioszkę do mniejszej. Nie można tego zrobić w życiu, ale można to zrobić w programowaniu. Ale jest jedno zastrzeżenie. Jeśli spróbujemy umieścić wartość intw zmiennej short, nie będzie to takie proste. W końcu w zmiennej może zmieścić się tylko 16 bitów informacji short, ale wartość intzajmuje 32 bity! W rezultacie przesyłana wartość będzie zniekształcona. Kompilator zwróci nam błąd („ stary, robisz coś podejrzanego! ”), ale jeśli wyraźnie określimy, na jaki typ rzutujemy naszą wartość, i tak wykona taką operację.
public class Main {

   public static void main(String[] args) {

       int bigNumber = 10000000;

       bigNumber = (short) bigNumber;

       System.out.println(bigNumber);

   }

}
W powyższym przykładzie właśnie to zrobiliśmy. Operację zakończono, lecz ponieważ shortw zmiennej zmieściło się tylko 16 z 32 bitów, ostateczna wartość została zniekształcona i w rezultacie otrzymaliśmy liczbę -27008 . Ta operacja nazywa się jawną konwersją lub zawężaniem .

Przykłady wydłużania i skracania typów referencyjnych

Teraz porozmawiamy o tych samych operacjach, ale nie można ich zastosować do typów pierwotnych, ale do obiektów i zmiennych referencyjnych ! Jak to działa w Javie? Właściwie całkiem proste. Istnieją obiekty, które nie są ze sobą powiązane. Logiczne byłoby założenie, że nie można ich konwertować na siebie ani jawnie, ani automatycznie:
public class Cat {
}

public class Dog {
}

public class Main {

   public static void main(String[] args) {

       Cat cat = new Dog();//błąd!

   }

}
Tutaj oczywiście otrzymamy błąd. Klasy nie CatDogze sobą powiązane i nie napisaliśmy „konwertera” między sobą. Logiczne jest, że nie będziemy w stanie tego zrobić: kompilator nie ma pojęcia, jak konwertować te obiekty między sobą. Co innego, jeśli obiekty są ze sobą połączone! Jak? Przede wszystkim wykorzystanie dziedziczenia. Spróbujmy stworzyć system małych klas z dziedziczeniem. Będziemy mieć ogólną klasę reprezentującą zwierzęta:
public class Animal {

   public void introduce() {

       System.out.println("i'm Animal");
   }
}
Zwierzęta, jak wiadomo, są domowe i dzikie:
public class WildAnimal extends Animal {

   public void introduce() {

       System.out.println("i'm WildAnimal");
   }
}

public class Pet extends Animal {

   public void introduce() {

       System.out.println("i'm Pet");
   }
}
Weźmy na przykład psy - psa domowego i kojota:
public class Dog extends Pet {

   public void introduce() {

       System.out.println("i'm Dog");
   }
}





public class Coyote extends WildAnimal {

   public void introduce() {

       System.out.println("i'm Coyote");
   }
}
Nasze zajęcia są celowo najbardziej prymitywne, aby ułatwić ich postrzeganie. Pola tutaj tak naprawdę nie są nam potrzebne, wystarczy jedna metoda. Spróbujmy uruchomić następujący kod:
public class Main {

   public static void main(String[] args) {

       Animal animal = new Pet();
       animal.introduce();
   }
}
Jak myślisz, co zostanie wyprowadzone na konsolę? introduceCzy klasa Petlub metoda klasowa będzie działać Animal? Zanim będziesz kontynuować czytanie, spróbuj uzasadnić swoją odpowiedź. A oto wynik! i'm Pet Dlaczego odpowiedź okazała się taka? To proste. Mamy zmienną nadrzędną i obiekt podrzędny. Przez pisanie:
Animal animal = new Pet();
Rozszerzyliśmy typ referencyjnyPet i zapisaliśmy jego obiekt w zmiennej Animal. Podobnie jak w przypadku typów pierwotnych, rozszerzanie typów referencyjnych w Javie odbywa się automatycznie. Nie ma potrzeby pisania w tym celu dodatkowego kodu. Teraz mamy obiekt potomny dołączony do odwołania nadrzędnego, w wyniku czego widzimy, że metoda jest wywoływana w klasie potomnej. Jeśli nadal nie do końca rozumiesz, dlaczego ten kod działa, przepisz go prostym językiem:
Животное животное = new ДомашнееЖивотное();
Nie ma z tym problemu, prawda? Wyobraź sobie, że to prawdziwe życie, a łączem w tym przypadku jest prosta papierowa przywieszka z napisem „Zwierzę”. Jeśli weźmiesz taką kartkę papieru i przymocujesz ją do obroży dowolnego zwierzaka, wszystko będzie dobrze. Każde zwierzę to nadal zwierzę! Proces odwrotny, czyli przejście w dół drzewa spadkowego do spadkobierców, jest zawężeniem:
public class Main {

   public static void main(String[] args) {

       WildAnimal wildAnimal = new Coyote();

       Coyote coyote = (Coyote) wildAnimal;

       coyote.introduce();
   }
}
Jak widać, tutaj wyraźnie wskazujemy, do której klasy chcemy rzucić nasz obiekt. Poprzednio mieliśmy zmienną WildAnimal, a teraz Coyote, która idzie w dół drzewa dziedziczenia. Logiczne jest, że kompilator nie pominie takiej operacji bez wyraźnego wskazania, ale jeśli określisz typ w nawiasie, wszystko będzie działać. Rozszerzanie i kurczenie się typów referencyjnych - 2 Spójrzmy na inny przykład, bardziej interesujący:
public class Main {

   public static void main(String[] args) {

       Pet pet = new Animal();//błąd!
   }
}
Kompilator zgłasza błąd! Jaki jest powód? Faktem jest, że próbujesz przypisać obiekt nadrzędny do zmiennej podrzędnej. Innymi słowy, chcesz to zrobić:
ДомашнееЖивотное домашнееЖивотное = new Животное();
Ale może jeśli wyraźnie wskażemy typ, na który próbujemy rzutować, to nam się uda? Liczby wydają się działać, spróbujmy! :)
public class Main {

   public static void main(String[] args) {

       Pet pet = (Pet) new Animal();
   }
}
Wyjątek w wątku „main” java.lang.ClassCastException: Nie można rzucić zwierzęcia na Pet. Błąd! Kompilator tym razem nie narzekał, ale w rezultacie otrzymaliśmy wyjątek. Znamy już powód: próbujemy przypisać obiekt nadrzędny do zmiennej podrzędnej. Dlaczego właściwie nie da się tego zrobić? Ponieważ nie wszystkie zwierzęta są zwierzętami domowymi. Utworzyłeś obiekt Animali próbujesz przypisać go do zmiennej Pet. Ale na przykład kojot jest także Animal, choć nie jest Pet, zwierzęciem domowym. Innymi słowy, kiedy piszesz:
Pet pet = (Pet) new Animal();
Może tam new Animal()przebywać każde zwierzę i nie musi to być domowe! Naturalnie twoja zmienna Pet petnadaje się tylko do przechowywania zwierząt domowych (i ich potomków), a nie dla wszystkich. Dlatego dla takich przypadków stworzono w Javie specjalny wyjątek – ClassCastExceptionbłąd podczas rzutowania klas. Powiedzmy to jeszcze raz, żeby było jaśniej. Zmienna nadrzędna (odniesienie) może wskazywać na obiekt klasy potomnej:
public class Main {

   public static void main(String[] args) {

       Pet pet =  new Pet();
       Animal animal = pet;

       Pet pet2 = (Pet) animal;
       pet2.introduce();
   }
}
Na przykład tutaj nie będziemy mieli żadnych problemów. Mamy obiekt Pet, na który wskazuje łącze Pet. Następnie nowy link zaczął wskazywać na ten sam obiekt Animal. Następnie wykonujemy konwersję animaldo Pet. Swoją drogą, dlaczego to zrobiliśmy? Ostatnim razem mamy wyjątek! Ponieważ tym razem naszym oryginalnym obiektem jest Pet pet!
Pet pet =  new Pet();
W poprzednim przykładzie był to obiekt Animal:
Pet pet = (Pet) new Animal();
Do zmiennej potomnej nie można przypisać obiektu nadrzędnego. Wręcz przeciwnie, możesz to zrobić.
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION