1. Wszystkie klasy są dziedziczone zObject
Wszystkie klasy w Javie są niejawnie (potajemnie) dziedziczone z Object
.
Czym jest dziedziczenie i jak działa w Javie, przeanalizujemy w zadaniu Java Core. Teraz rozważymy jeden prosty fakt, który z tego wynika:
Zmiennej typu Object
można przypisać obiekt dowolnej klasy. Przykład:
Kod | Notatka |
---|---|
|
o Odwołanie do obiektu typu jest przechowywane w zmiennejScanner |
|
o Odwołanie do obiektu typu jest przechowywane w zmiennejString |
|
o Odwołanie do obiektu typu jest przechowywane w zmiennejInteger |
|
o Odwołanie do obiektu typu jest przechowywane w zmiennejString |
Na tym kończą się dobre wieści. Kompilator nie śledzi dokładnie, jaki typ obiektu był przechowywany w zmiennej typu Object
, dlatego nie można wywołać metod, które miał przechowywany obiekt, ale których nie ma zmienna Object
typu .
Jeśli potrzebujesz wywołać metody takiego obiektu, to najpierw musisz zapisać do niego odwołanie w zmiennej odpowiedniego typu, a dopiero potem wywołać metody na tej zmiennej:
Kod | Notatka |
---|---|
|
Program nie skompiluje się. Klasa Object nie ma metody nextInt() . |
|
Tak to będzie działać. Tutaj zapisujemy odwołanie do obiektu typu Scanner do zmiennej typu Scanner za pomocą operatora rzutowania . |
Tylko dlatego, że zmiennej typu Object
nie można przypisać do zmiennej typu Scanner, nawet jeśli zmienna typu Object
przechowuje odwołanie do obiektu typu Scanner
. Ale można to zrobić, jeśli użyjesz znanego ci operatora rzutowania typów . Ogólnie wygląda to tak:
Тип Nazwa1 = (Тип) Nazwa2;
Gdzie Nazwa1
jest nazwą zmiennej typu Тип
i Nazwa2
jest nazwą zmiennej typu Object
, która zawiera odwołanie do obiektu typu Тип
.
Odlewanie typu
Jeśli typy zmiennej i obiektu nie pasują do siebie, wystąpi błąd ClassCastException
. Przykład:
Kod | Notatka |
---|---|
|
Podczas wykonywania wystąpi błąd: tutaj zostanie zgłoszony wyjątek ClassCastException |
Java ma sposób na obejście tego błędu: istnieje sposób sprawdzenia, jaki typ faktycznie znajduje się w zmiennej :
Nazwa instanceof Тип
Operator instanceof
sprawdza, czy zmienna jest Nazwa
obiektem typu Тип
.
Przykładem jest znalezienie ciągu znaków wśród tablicy danych:
Kod | Notatka |
---|---|
|
Autoboxing zamieni te wartości w Integer , String i Double . Przejrzyj tablicę obiektów Jeśli obiekt ma typ String Zapisz go jako zmienną typu String Wyświetl zmienną na ekranie. |
2. Przyczyna występowania wzorców (kolekcji)
Powrót do kolekcji.
Gdy programiści Java po raz pierwszy stworzyli tę klasę ArrayList
, chcieli uczynić ją ogólną, tak aby mogła przechowywać obiekty dowolnego typu. Dlatego do przechowywania elementów użyli tablicy typu Object
.
Siła tego podejścia polega na tym, że do kolekcji można dodać obiekt dowolnego typu.
Cóż, jest kilka słabych.
Wada 1.
Zawsze musiałem napisać operator konwersji typu podczas pobierania elementów z kolekcji:
Kod | Notatka |
---|---|
|
Utwórz obiekt kolekcji do przechowywania odwołań do obiektów typu Object Wypełnij kolekcję liczbami 10 , 20 , ... 100 ; Podsumuj elementy kolekcji Musisz użyć rzutowania typów |
Wada 2.
Nie było gwarancji, że w kolekcji przechowywane są elementy określonego typu
Kod | Notatka |
---|---|
|
Tworzymy obiekt kolekcji do przechowywania referencji do obiektów typu Object Wypełnij zbiór liczbami typu Double : 0.0 , 2.5 , 5.0 , ... Sumuj elementy zbioru Wystąpi błąd: Double nie można rzutować typu na typInteger |
Dane w zbiorze można uzupełnić w dowolnym miejscu:
- w innej metodzie
- w innym programie
- załadować z pliku
- odbierać przez sieć
Wada 3.
Dane kolekcji mogą zostać przypadkowo zmienione z powodu niewiedzy.
Możesz przekazać kolekcję wypełnioną Twoimi danymi do jakiejś metody, a ta metoda, napisana przez zupełnie innego programistę, doda swoje dane do Twojej kolekcji.
Z nazwy kolekcji nie jest jasne, jakie typy danych mogą być w niej przechowywane. I nawet jeśli nadasz zmiennej taką nazwę, referencja do niej może zostać przekazana do kilkunastu metod, a tam nic nie będzie wiadomo o oryginalnej nazwie zmiennej.
3. Leki generyczne
Wszystkie te problemy są eliminowane przez tak fajną rzecz w Javie, jak generyczne (Generics).
Rodzaje w Javie oznaczają możliwość dodawania typów parametrów do typów. W ten sposób uzyskuje się złożone typy złożone. Taki typ złożony wygląda ogólnie tak:
ОсновнойТип<ТипПараметр>
Wszystko razem - to jest dokładnie ten typ. I może być używany tam, gdzie normalnie używałbyś typów.
Kod | Opis |
---|---|
|
Tworzenie zmiennych |
|
Tworzenie obiektów |
|
Tworzenie tablic |
W takim zbiorze mogą być przechowywane tylko zmienne typu Integer
:
Kod | Opis |
---|---|
|
Kolekcja typu ArrayList z elementami typu Integer So you can I so you can: zadziała
autoboksowanie
To niemożliwe: błąd kompilacji |
Dowiesz się, jak tworzyć własne klasy z typami parametrów w zadaniu Java Collections. Teraz przeanalizujemy, jak go używać i jak działa.
4. Jak działają leki generyczne
W rzeczywistości leki generyczne działają w strasznie prymitywny sposób.
Kompilator po prostu zastępuje typ parametrem typem bez parametru. A podczas interakcji ze swoimi metodami dodaje operację rzutowania typu do typu parametru:
Kod | Co zrobi kompilator |
---|---|
|
|
|
|
|
|
|
|
Powiedzmy, że mamy kod metody, która sumuje liczby w zbiorze liczb całkowitych:
Kod | Co zrobi kompilator |
---|---|
|
|
Te. w rzeczywistości generyczne są rodzajem cukru składniowego, jak autoboxing, tylko więcej. Dzięki autoboxingowi kompilator dodaje dla nas metody konwersji typów int
do Integer
iz powrotem, a dla typów generycznych dodaje operatory rzutowania typów.
Po tym, jak kompilator skompiluje twój kod z typami ogólnymi, wszystkie klasy z parametrami zostały przekonwertowane na same klasy i operatory rzutowania. Informacje o tym, jakie typy-parametry były pierwotnie dla zmiennych typów złożonych, zostały utracone. Ten efekt jest również nazywany wymazywaniem czcionek .
Czasami programistom, którzy piszą swoje klasy z typami parametrów, bardzo brakuje informacji o typach, które są tam przekazywane jako parametry. Jak sobie z tym poradzić i co z tego wyniknie, dowiesz się w zadaniu Java Collections.
5. Kilka faktów na temat leków generycznych
Kilka ciekawszych faktów na temat leków generycznych.
Klasy mogą mieć więcej niż jeden typ parametru, ale kilka. Wygląda to mniej więcej tak:
ОсновнойТип<ТипПараметр1, ТипПараметр2, ТипПараметр3>
Ściśle mówiąc, nie jest to zaskakujące. Tam, gdzie kompilator może dodać operatora rzutowania do jednego typu, może dodać więcej niż jeden.
Przykłady:
Kod | Notatka |
---|---|
|
pierwszy parametr metody put jest typu Integer , drugi jest typuString |
Również typy złożone mogą być również używane jako parametry . Wygląda to mniej więcej tak:
ОсновнойТип<ТипПараметр<ТипПараметрПараметра>>
Powiedzmy, że chcemy utworzyć listę, która będzie przechowywać listy ciągów znaków. W takim przypadku otrzymamy coś takiego jak ten kod:
// список приветствий
ArrayList<String> listHello = new ArrayList<String>();
listHello.add("Cześć");
listHello.add("Hi");
// список прощаний
ArrayList<String> listBye = new ArrayList<String>();
listBye.add("Пока");
listBye.add("Good Bye");
// список списков
ArrayList<ArrayList<String>> lists = new ArrayList<ArrayList<String>>();
lists.add(listHello);
lists.add(listBye);
GO TO FULL VERSION