MERHABA! Bugünün dersinde jenerikleri incelemeye devam edeceğiz. Olduğu gibi, bu büyük bir konu ama bundan kaçış yok — dilin son derece önemli bir parçası :) Jeneriklerle ilgili Oracle belgelerini incelediğinizde veya çevrimiçi eğitimleri okuduğunuzda, somutlaştırılamayan türler ve terimleriyle karşılaşacaksınız. şeyleştirilebilir tipler Gerçekleştirilebilir bir tür, çalışma zamanında bilgilerinin tamamen mevcut olduğu bir türdür. Java'da bu tür türler, ilkelleri, ham türleri ve genel olmayan türleri içerir. Buna karşılık, somutlaştırılamayan türler, bilgileri çalışma zamanında silinen ve erişilemez hale gelen türlerdir. Olduğu gibi, bunlar jeneriktir -
Yığın kirliliği aşağıdaki durumda olabilir:
List<String>
, List<Integer>
, vb.
Bu arada, varargs'ın ne olduğunu hatırlıyor musun?
Unuttuysanız, bu değişken uzunluklu bir argümandır. Metodumuza kaç argüman aktarılabileceğini bilmediğimiz durumlarda faydalıdırlar. Örneğin, bir yöntemi olan bir hesap makinesi sınıfımız varsasum
. Yöntem sum()
, 2 veya 3 veya 5 veya istediğiniz kadar sayı alabilir. sum()
Her olası bağımsız değişken sayısı için yöntemi aşırı yüklemek çok garip olurdu . Bunun yerine şunu yapabiliriz:
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));
}
}
Konsol çıktısı:
15
11
Bu bize vararg'ları jeneriklerle birlikte kullanırken bazı önemli özelliklerin olduğunu gösterir. Aşağıdaki koda bakalım:
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>(), // This is okay
"Leonardo da Vinci",
"Vasco de Gama"
);
// but here we get a warning
addAll(new ArrayList<Pair<String, String>>(),
new Pair<String, String>("Leonardo", "da Vinci"),
new Pair<String, String>("Vasco", "de Gama")
);
}
}
Yöntem , a ve herhangi bir sayıda nesneyi addAll()
girdi olarak alır ve ardından tüm bu nesneleri listeye ekler. Yöntemde , yöntemimizi iki kez çağırıyoruz . İlk durumda, . Burada her şey yolunda. İkinci durumda , . Ancak burada beklenmedik bir şekilde bir uyarı alıyoruz: List<E>
E
main()
addAll()
List
Pair<String, String>
List
Unchecked generics array creation for varargs parameter
Bu ne anlama gelir? Neden bir uyarı alıyoruz ve neden bir uyarı var array
? Sonuçta, kodumuzda array
! İkinci durumla başlayalım. Uyarı, bir diziden bahsediyor çünkü derleyici değişken uzunluklu bağımsız değişkeni (varargs) bir diziye dönüştürüyor. Başka bir deyişle, yöntemimizin imzası addAll()
:
public static <E> void addAll(List<E> list, E... array)
Aslında şöyle görünüyor:
public static <E> void addAll(List<E> list, E[] array)
Yani, yöntemde main()
derleyici kodumuzu şuna dönüştürür:
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")
}
);
}
Bir String
dizi gayet iyi. Ancak bir Pair<String, String>
dizi değildir. Sorun şu ki, Pair<String, String>
şeyleştirilebilir olmayan bir tür. Derleme sırasında, tür bağımsız değişkenleriyle (<String, String>) ilgili tüm bilgiler silinir. Tanımlanamaz türde diziler oluşturmaya Java'da izin verilmez . El ile bir Pair<String, String> dizisi oluşturmaya çalışırsanız bunu görebilirsiniz.
public static void main(String[] args) {
// Compilation error Generic array creation
Pair<String, String>[] array = new Pair<String, String>[10];
}
Nedeni açık: güvenlik yazın. Hatırlayacağınız gibi dizi oluştururken mutlaka dizinin hangi nesneleri (veya primitifleri) saklayacağını belirtmeniz gerekir.
int array[] = new int[10];
Önceki derslerimizden birinde yazı silme işlemini detaylı bir şekilde incelemiştik. Pair
Bu durumda, tip silme, nesnelerin çiftleri sakladığı bilgileri kaybetmemize neden olur <String, String>
. Diziyi oluşturmak güvensiz olur. Değişkenler ve jenerikler içeren yöntemleri kullanırken , tip silmeyi ve bunun nasıl çalıştığını hatırladığınızdan emin olun. Yazdığınız koddan kesinlikle eminseniz ve herhangi bir sorun çıkarmayacağını biliyorsanız, açıklamaları kullanarak varargs ile ilgili uyarıları kapatabilirsiniz . @SafeVarargs
@SafeVarargs
public static <E> void addAll(List<E> list, E... array) {
for (E element : array) {
list.add(element);
}
}
Bu ek açıklamayı yönteminize eklerseniz, daha önce karşılaştığımız uyarı görünmez. Vararg'ları jenerik ilaçlarla kullanırken ortaya çıkabilecek başka bir sorun da yığın kirliliğidir. 
import java.util.ArrayList;
import java.util.List;
public class Main {
static List<String> polluteHeap() {
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 = polluteHeap();
System.out.println(stringsWithHeapPollution.get(0));
}
}
Konsol çıktısı:
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
Basit bir ifadeyle, yığın kirliliği, türdeki nesnelerin A
yığında olması gerektiği, ancak türdeki nesnelerin, B
tür güvenliği ile ilgili hatalar nedeniyle orada sona erdiği zamandır. Örneğimizde, olan tam olarak budur. İlk olarak, ham değişkeni yarattık numbers
ve ArrayList<Number>
ona genel bir koleksiyon ( ) atadık. 1
Ardından sayıyı koleksiyona ekledik .
List<String> strings = numbers;
Bu satırda derleyici " Unchecked atama... " uyarısı vererek olası hatalar konusunda bizi uyarmaya çalıştı ama biz dikkate almadık. List<String>
Sonunda , type türünde bir genel koleksiyona işaret eden türde bir genel değişken elde ederiz ArrayList<Number>
. Açıkçası, bu durum sorun yaratabilir! Ve öyle de oluyor. Yeni değişkenimizi kullanarak koleksiyona bir dize ekliyoruz. Artık yığın kirliliğimiz var - parametreleştirilmiş koleksiyona bir sayı ve ardından bir dize ekledik. Derleyici bizi uyardı, ancak uyarısını dikkate almadık. ClassCastException
Sonuç olarak, sadece program çalışırken bir tane alırız . Peki bunun varargs ile ne ilgisi var? Vararg'ları jenerik ilaçlarla kullanmak kolayca yığın kirliliğine yol açabilir. İşte basit bir örnek:
import java.util.Arrays;
import java.util.List;
public class Main {
static void polluteHeap(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");
polluteHeap(cars1, cars2);
}
}
Burada neler oluyor? Tip silme nedeniyle, değişken uzunluklu argümanımız
List<String>...stringsLists
bir listeler dizisi haline gelir, yani List[]
bilinmeyen türdeki nesnelerin (varargs'ın derleme sırasında düzenli bir diziye dönüştüğünü unutmayın). Bu nedenle, onu yöntemin ilk satırındaki değişkene kolayca atayabiliriz Object[] array
— listemizdeki nesnelerin türü silindi! Object[]
Ve şimdi , Java'daki tüm nesneler miras aldığı için, herhangi bir şey ekleyebileceğimiz bir değişkenimiz var Object
! İlk başta, yalnızca bir dizi dizi listemiz var. Ancak tip silme ve vararg kullanımımız sayesinde, yaptığımız bir sayı listesini kolayca ekleyebiliriz. Sonuç olarak, farklı türdeki nesneleri karıştırarak yığını kirletiriz. ClassCastException
Diziden bir dize okumaya çalıştığımızda sonuç yine farklı olacaktır . Konsol çıktısı:
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
Görünüşte basit bir mekanizma olan vararglar bu tür beklenmedik sonuçlara yol açabilir :) Ve böylece, bugünkü dersimiz burada sona eriyor. Birkaç görevi çözmeyi unutmayın ve zamanınız ve enerjiniz varsa, biraz daha çalışın. " Etkili Java " kendini okumaz! :) Bir sonrakine kadar!
GO TO FULL VERSION