Сәлеметсіз бе! Бүгінгі сабақта біз генериктерді оқуды жалғастырамыз. Бұл үлкен тақырып, бірақ баратын жер жоқ - бұл тілдің өте маңызды бөлігі :) Генериктерге арналған Oracle құжаттамасын оқығанда немесе Интернетте нұсқаулықтарды оқығанда, сіз терминдерді кездестіресіз. Қайталанbyteын түрлер және қайталанатын түрлер . «Қайталанатын» сөздің қай түріне жатады? Ағылшын тілінде бәрі жақсы болса да, оны кездестіру екіталай. Аударып көрейік!
*рахмет Google, сіз көп көмектестіңіз -_-*
Қайталанатын түрі - ақпараты орындалу уақытында толық қолжетімді болатын түрі. Java тілінде оларға примитивтер, raw-типтер және жалпы емес типтер жатады. Керісінше, Қайталанbyteын түрлер - ақпараты өшірілетін және орындау уақытында қолжетімсіз болатын түрлер. Бұл жай ғана генериктер - List<String> , List<Integer> және т.б.
Айтпақшы, вараргтардың не екені есіңізде ме ?
Егер сіз ұмытып қалсаңыз, бұл айнымалы ұзындық дәлелдері. Олар біздің әдісімізге қанша аргумент беруге болатынын нақты білмейтін жағдайларда пайдалы. Мысалы, бізде калькулятор класы болса және оның әдісі болсаsum
. Сіз әдіске sum()
2 санды, 3, 5 немесе қалағаныңызша бере аласыз . sum()
Барлық ықтимал нұсқаларды ескеру үшін әдісті әр уақытта шамадан тыс жүктеу өте таңқаларлық болар еді . Оның орнына біз мұны істей аламыз:
public class SimpleCalculator {
public static int sum(int...numbers) {
int result = 0;
for(int i : numbers) {
result += i;
}
return result;
}
public static void main(String[] args) {
System.out.println(sum(1,2,3,4,5));
System.out.println(sum(2,9));
}
}
Консоль шығысы:
15
11
varargs
Сонымен, генериктермен бірге қолданғанда кейбір маңызды ерекшеліктер бар. Мына codeты қарастырайық:
import javafx.util.Pair;
import java.util.ArrayList;
import java.util.List;
public class Main {
public static <E> void addAll(List<E> list, E... array) {
for (E element : array) {
list.add(element);
}
}
public static void main(String[] args) {
addAll(new ArrayList<String>(), // здесь все нормально
"Leonardo da Vinci",
"Vasco de Gama"
);
// а здесь мы получаем предупреждение
addAll(new ArrayList<Pair<String, String>>(),
new Pair<String, String>("Leonardo", "da Vinci"),
new Pair<String, String>("Vasco", "de Gama")
);
}
}
Әдіс тізімді және нысандардың кез келген санын addAll()
кіріс ретінде қабылдайды , содан кейін осы нысандардың барлығын тізімге қосады. Әдісте біз әдісімізді екі рет шақырамыз . Бірінші рет біз екі тұрақты жолды қосамыз . Мұнда бәрі жақсы. Екінші рет біз екі нысанды қосамыз . Міне, біз кенеттен ескерту аламыз: List<E>
E
main()
addAll()
List
List
Pair<String, String>
Unchecked generics array creation for varargs parameter
Бұл нені білдіреді? Неліктен ескерту аламыз және оның оған қандай қатысы бар array
? Array
- бұл массив және біздің codeта массивтер жоқ! Екіншіден бастайық. Ескерту массив туралы айтады, себебі компилятор айнымалы ұзындық аргументтерін (varargs) массивке түрлендіреді. Басқаша айтқанда, біздің әдісіміздің қолтаңбасы addAll()
:
public static <E> void addAll(List<E> list, E... array)
Бұл іс жүзінде келесідей көрінеді:
public static <E> void addAll(List<E> list, E[] array)
Яғни әдісте main()
компилятор біздің codeты келесіге түрлендіреді:
public static void main(String[] args) {
addAll(new ArrayList<String>(),
new String[] {
"Leonardo da Vinci",
"Vasco de Gama"
}
);
addAll(new ArrayList<Pair<String,String>>(),
new Pair<String,String>[] {
new Pair<String,String>("Leonardo","da Vinci"),
new Pair<String,String>("Vasco","de Gama")
}
);
}
Массивпен бәрі жақсы String
. Бірақ массивпен Pair<String, String>
- жоқ. Өйткені, Pair<String, String>
бұл қайталанbyteын түрі. Компиляция кезінде параметр түрлері (<Жол, Жол>) туралы барлық ақпарат жойылады. Java тілінде қайталанbyteын типтен массивтер жасауға рұқсат етілмейді . Pair<String, String> массивін қолмен жасауға әрекеттенсеңіз, мұны тексеруге болады
public static void main(String[] args) {
// ошибка компиляции! Generic array creation
Pair<String, String>[] array = new Pair<String, String>[10];
}
Себебі анық - типті қауіпсіздік. Естеріңізде болса, массив құру кезінде бұл массив қандай нысандарды (немесе қарабайырларды) сақтайтынын көрсетуіңіз керек.
int array[] = new int[10];
Өткен сабақтардың бірінде біз типті өшіру механизмін егжей-тегжейлі қарастырдық. Осылайша, бұл жағдайда, типтерді өшіру нәтижесінде біз Pair
жұптар біздің нысандарда сақталған ақпаратты жоғалттық <String, String>
. Массив жасау қауіпті болады. Әдістерді varargs
және генериктерді пайдаланған кезде, түрін өшіру және оның қалай жұмыс істейтінін есте сақтаңыз. Егер сіз жазған codeқа толық сенімді болсаңыз және оның ешқандай қиындық тудырмайтынын білсеңіз, varargs
annotationны пайдаланып онымен байланысты ескертулерді өшіруге болады.@SafeVarargs
@SafeVarargs
public static <E> void addAll(List<E> list, E... array) {
for (E element : array) {
list.add(element);
}
}
Бұл annotationны әдісіңізге қоссаңыз, бұрын кездескен ескерту пайда болмайды. Генериктерді бірге пайдаланудағы тағы бір мүмкін мәселе varargs
- үйінділердің ластануы. Ластану келесі жағдайларда болуы мүмкін:
import java.util.ArrayList;
import java.util.List;
public class Main {
static List<String> makeHeapPollution() {
List numbers = new ArrayList<Number>();
numbers.add(1);
List<String> strings = numbers;
strings.add("");
return strings;
}
public static void main(String[] args) {
List<String> stringsWithHeapPollution = makeHeapPollution();
System.out.println(stringsWithHeapPollution.get(0));
}
}
Консоль шығысы:
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
Қарапайым тілмен айтқанда, үйінді ластануы 1 типті an objectілер үйіндіде болуы керек жағдай , бірақ типтегі нысандар қауіпсіздік қателеріне байланысты А
сонда аяқталады . B
Біздің мысалда осылай болады. Алдымен біз Raw айнымалысын жасап numbers
, оған жалпы жинақты тағайындадық ArrayList<Number>
. Осыдан кейін біз сол жерде нөмірді қостық 1
.
List<String> strings = numbers;
Бұл жолда компилятор « Тексерілмеген тапсырма... » ескертуін беру арқылы ықтимал қателер туралы ескертуге тырысты, бірақ біз оны елемедік. Нәтижесінде бізде типтің жалпы айнымалысы бар List<String>
, ол типтің жалпы жиынын көрсетеді ArrayList<Number>
. Бұл жағдай қиындыққа әкелуі мүмкін! Бұл болады. Жаңа айнымалы мәнді пайдалана отырып, коллекцияға жолды қосамыз. Үйінді ластанған - терілген жинаққа алдымен санды, содан кейін жолды қостық. Компилятор бізге ескертті, бірақ біз оның ескертуін елемедік, нәтижелерді ClassCastException
бағдарлама жұмыс істеп тұрған кезде ғана аламыз. Оған не қатысы бар varargs
? Генериктермен пайдалану үйінділердің ластануына оңай әкелуі мүмкін. varargs
Міне, қарапайым мысал:
import java.util.Arrays;
import java.util.List;
public class Main {
static void makeHeapPollution(List<String>... stringsLists) {
Object[] array = stringsLists;
List<Integer> numbersList = Arrays.asList(66,22,44,12);
array[0] = numbersList;
String str = stringsLists[0].get(0);
}
public static void main(String[] args) {
List<String> cars1 = Arrays.asList("Ford", "Fiat", "Kia");
List<String> cars2 = Arrays.asList("Ferrari", "Bugatti", "Zaporozhets");
makeHeapPollution(cars1, cars2);
}
}
Бұл жерде не болып жатыр? Түрді өшіруге байланысты, біздің параметр парақтарымыз (оларды ыңғайлы болу үшін «тізімдер» орнына «парақтар» деп атаймыз) -
List<String>...stringsLists
- парақтар массивіне айналады - List[]
белгісіз түрі бар (құрастыру нәтижесінде varargs кәдімгі массивке айналатынын ұмытпаңыз). Осының арқасында біз әдістің бірінші жолында айнымалыға оңай тапсырма жасай аламыз Object[] array
- түрлер парақтарымыздан өшірілді! Ал енді бізде түрдің айнымалысы бар Object[]
, оған біз кез келген нәрсені қоса аламыз - Java тіліндегі барлық нысандар мұрагер Object
! Дәл қазір бізде тек жол парақтары бар. Бірақ түрлерін пайдалану varargs
және өшіру арқасында біз оларға сандар парағын оңай қоса аламыз, бұл біз жасаймыз. Нәтижесінде әртүрлі типтегі заттарды араластыру арқылы үйінді ластаймыз. ClassCastException
Нәтиже массивтен жолды оқу әрекеті кезінде бірдей ерекшелік болады . Консоль шығысы:
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
Қарапайым болып көрінетін механизмді қолданудың күтпеген салдары осылар varargs
:) Міне, біздің бүгінгі лекциямыз аяқталды. Бірнеше мәселені шешуді ұмытпаңыз, егер сізде уақыт пен күш қалса, қосымша әдебиеттерді оқыңыз. « Тиімді Java » өзін оқымайды! :) Кездескенше!
GO TO FULL VERSION