1. Всички класове наследяватObject
Всички класове в Java имплицитно наследяват Objectкласа.
Ще анализираме Howво е наследяването и How работи в Java в търсенето на Java Core. Засега ще разгледаме един прост факт, който следва от това:
Обект от всеки клас може да бъде присвоен на Objectпроменлива. Пример:
| Код | Забележка |
|---|---|
|
Променливата oсъхранява препратка към Scannerобект |
|
Променливата oсъхранява препратка към Stringобект |
|
Променливата oсъхранява препратка към Integerобект |
|
Променливата oсъхранява препратка към Stringобект |
Тук добрите новини свършват. Компилаторът не следи оригиналния тип обект, записан в Objectпроменлива, така че няма да можете да извиквате методи на записания обект , различни от методите на Objectкласа.
Ако трябва да извикате методите, свързани с оригиналния тип на обекта, тогава трябва първо да запишете препратка към него в променлива от правилния тип и след това да извикате методите на тази променлива:
| Код | Забележка |
|---|---|
|
Програмата няма да се компorра. Класът Objectняма nextInt()метод. |
|
Това ще свърши работа. Тук запазваме препратка към Scannerобект в Scannerпроменлива, използвайки оператор за придаване на тип . |
Не можете просто да отидете и да присвоите Objectпроменлива на променлива на Scanner, дори ако Objectпроменливата съхранява препратка към Scannerобект. Но можете да направите това, ако използвате оператора typecast , за който вече знаете. Това е общият му вид:
Type name1 = (Type) name2;
Къде name1е името на Typeпроменлива и name2е името на Objectпроменлива, която съхранява препратка към Typeобект.
Преобразуване на типове
Ако типът на променливата и типът на обекта не съвпадат, тогава ClassCastExceptionще бъде хвърлено a. Пример:
| Код | Забележка |
|---|---|
|
Ще възникне грешка по време на изпълнение: тук ще бъде изведено a ClassCastException |
Има начин да избегнете тази грешка в Java: правим това, като проверяваме типа на обекта, съхранен в променлива :
name instanceof Type
Операторът instanceofпроверява дали nameпроменливата е Typeобект.
Като пример, нека намерим низ в масив от различни обекти:
| Код | Забележка |
|---|---|
|
Autoboxing ще преобразува тези стойности съответно в Integer, Stringи Double. Цикъл върху масива от обекти Ако обектът е StringЗапазете го в Stringпроменлива Показване на променливата на екрана. |
2. Защо се появиха генериците — колекции
Да се върнем към колекциите.
Веднага след като Java разработчиците създадоха ArrayListкласа, те искаха да го направят универсален, така че да може да съхранява всяHowъв тип обект. Така че те използваха масив от Objects за съхраняване на елементите.
Силата на този подход е, че можете да добавите обект от всяHowъв тип към колекцията.
Разбира се, има няколко слабости.
Недостатък 1.
Винаги е било необходимо да се напише оператор за преобразуване на тип, когато се извличат елементи от колекция:
| Код | Забележка |
|---|---|
|
Създайте колекция за съхраняване на препратки към Objectобекти . Попълнете колекцията с числа 10, 20, ... 100; Обобщете елементите на колекцията. Необходимо е преобразуване на типове |
Недостатък 2.
Нямаше гаранция, че колекцията съдържа определен тип елемент
| Код | Забележка |
|---|---|
|
Създайте колекция за съхраняване на препратки към Objectобекти Ние запълваме колекцията с числа, представени като Doubleобекти: 0.0, 2.5, 5.0, ... Сумирайте елементите на колекцията Ще има грешка: a Doubleне може да бъде преобразувано вInteger |
Данните могат да бъдат поставени в колекцията навсякъде:
- в друг метод
- в друга програма
- от файл
- по мрежата
Недостатък 3.
Данните в колекцията могат да бъдат променени случайно.
Можете да предадете колекция, пълна с вашите данни, към няHowъв метод. Този метод, написан от друг програмист, добавя своите данни към вашата колекция.
Името на колекцията не показва ясно кои типове данни могат да се съхраняват в нея. И дори ако дадете ясно име на вашата променлива, препратка към нея може да бъде предадена на дузина методи и тези методи определено няма да знаят нищо за оригиналното име на променливата.
3. Генерични лекарства

В Java всички тези проблеми се елиминират от това страхотно нещо, наречено генерични.
В Java генеричните средства означават възможността за добавяне на параметри на типове към типове. Резултатът е сложен композитен тип. Общият изглед на такъв съставен тип е следният:
ClassName<TypeParameter>
Това е общ клас. И може да се използва навсякъде, където обикновено използвате класове.
| Код | Описание |
|---|---|
|
Създаване на променливи |
|
Създаване на обекти |
|
Създаване на масиви |
IntegerВ такава колекция могат да се съхраняват само променливи:
| Код | Описание |
|---|---|
|
ArrayListколекция с Integerелементи Това е разрешено И това също ще работи
Автобокс
Но това не е позволено: грешка при компorране |
Ще научите How да създавате свои собствени класове с параметри на типа в търсенето на Java Collections. Засега ще разгледаме How да ги използваме и How работят.
4. Как работят генеричните лекарства
Всъщност генериците са ужасно примитивни.
Компилаторът просто заменя генеричните типове с обикновени типове. Но когато се използват методи от общ тип, компилаторът добавя оператор за преобразуване на типа за преобразуване на параметри към параметрите на типа:
| Код | Какво прави компилаторът |
|---|---|
|
|
|
|
|
|
|
|
Да предположим, че имаме метод, който сумира числата в колекция от цели числа:
| Код | Какво прави компилаторът |
|---|---|
|
|
С други думи, генериците са вид синтактична захар, точно като autoboxing, но малко повече. С autoboxing компилаторът добавя методи за преобразуване на an intв an Integerи обратно, а за генеричните добавя оператори за придаване на тип.
След като компилаторът компorра вашите генерични класове с параметри на типа, те просто се преобразуват в обикновени класове и оператори за преобразуване на типа. Информацията за аргументите на типа, предадени на променливи от общи типове, се губи. Този ефект се нарича още изтриване на типа .
Понякога програмистите, които пишат генерични класове (класове с параметри на типа), наистина се нуждаят от информацията за типовете, предадени като аргументи. В търсенето на Java Collections ще научите How да се справите с това и Howво включва то.
5. Няколко факта за генериците
Ето още няколко интересни факта за генериците.
Класовете могат да имат няколко параметъра на типа. Изглежда нещо подобно:
ClassName<TypeParameter1, TypeParameter2, TypeParameter3>
Всъщност това не е изненадващо. Навсякъде, където компилаторът може да добави оператор за преобразуване към един тип, той може да добави множество оператори за преобразуване на типа.
Примери:
| Код | Забележка |
|---|---|
|
Първият putпараметър на метода е a Integer, а вторият е aString |
Генеричните типове също могат да се използват като параметри . Изглежда нещо подобно:
ClassName<TypeParameter<TypeParameterParameter>>
Да предположим, че искаме да създадем списък, който ще съхранява списъци с низове. В този случай ще получим нещо подобно:
// List of greetings
ArrayList<String> listHello = new ArrayList<String>();
listHello.add ("Hello");
listHello.add ("Hi");
// List of goodbyes
ArrayList<String> listBye = new ArrayList<String>();
listBye.add("Bye");
listBye.add ("Goodbye");
// List of lists
ArrayList<ArrayList<String>> lists = new ArrayList<ArrayList<String>>();
lists.add(listHello);
lists.add(listBye);
Генеричните типове (типове с параметри на типа) също могат да се използват като типове масиви. Изглежда нещо подобно:
ClassName<TypeParameter>[] array = new ClassName<TypeParameter>[size];
Тук не се случва нищо магическо: ъгловите скоби просто показват името на типа:
| Код | Негенеричен аналог |
|---|---|
|
|
|
|
|
|
GO TO FULL VERSION