Genel bir yöntem üzerinde birden fazla joker Java derleyici (ve bana!) yapar çok karışık
Hadi basit bir senaryo (see complete source on ideone.com) göz önünde bulundurun:
import java.util.*;
public class TwoListsOfUnknowns {
static void doNothing(List<?> list1, List<?> list2) { }
public static void main(String[] args) {
List<String> list1 = null;
List<Integer> list2 = null;
doNothing(list1, list2); // compiles fine!
}
}
İki joker List<String>
List<Integer>
doNothing
diyebilirsin yüzden ilgisiz. Diğer bir deyişle, iki ?
tamamen farklı bakabilirsiniz. Bu nedenle aşağıdaki beklendiği gibi, (also on ideone.com) derleme:
import java.util.*;
public class TwoListsOfUnknowns2 {
static void doSomethingIllegal(List<?> list1, List<?> list2) {
list1.addAll(list2); // DOES NOT COMPILE!!!
// The method addAll(Collection<? extends capture#1-of ?>)
// in the type List<capture#1-of ?> is not applicable for
// the arguments (List<capture#2-of ?>)
}
}
Şimdiye kadar çok iyi, ama çok kafa karıştırıcı olmaya başlar burada (126**):
import java.util.*;
public class LOLUnknowns1 {
static void probablyIllegal(List<List<?>> lol, List<?> list) {
lol.add(list); // this compiles!! how come???
}
}
Yukarıdaki kod Eclipse benim için derler ve ideone.com ama yazmalı? sun-jdk-1.6.0.17
List<List<Integer>> lol
TwoListsOfUnknowns
List<String> list
, benzer alakasız iki joker bir durumlar da var olması mümkün değil mi?
Beklendiği gibi, bu yöndeki derleme değil doğru aslında aşağıdaki hafif bir değişiklik, (as seen on ideone.com):
import java.util.*;
public class LOLUnknowns2 {
static void rightfullyIllegal(
List<List<? extends Number>> lol, List<?> list) {
lol.add(list); // DOES NOT COMPILE! As expected!!!
// The method add(List<? extends Number>) in the type
// List<List<? extends Number>> is not applicable for
// the arguments (List<capture#1-of ?>)
}
}
Derleyici işini yapıyor, ama o zaman bu (as seen on ideone.com) alacağız gibi görünüyor:
import java.util.*;
public class LOLUnknowns3 {
static void probablyIllegalAgain(
List<List<? extends Number>> lol, List<? extends Number> list) {
lol.add(list); // compiles fine!!! how come???
}
}
Yine, List<List<Integer>> lol
ve bu derleme gerekmez mi yani List<Float> list
, örneğin olabilir?
Aslında, hadi geri LOLUnknowns1
basit (iki sınırsız joker) gidin ve eğer herhangi bir şekilde probablyIllegal
çağırmak için deneyin. Deneyelim "kolay" dava ilk iki joker karakter (as seen on ideone.com) için aynı tipi seçin
import java.util.*;
public class LOLUnknowns1a {
static void probablyIllegal(List<List<?>> lol, List<?> list) {
lol.add(list); // this compiles!! how come???
}
public static void main(String[] args) {
List<List<String>> lol = null;
List<String> list = null;
probablyIllegal(lol, list); // DOES NOT COMPILE!!
// The method probablyIllegal(List<List<?>>, List<?>)
// in the type LOLUnknowns1a is not applicable for the
// arguments (List<List<String>>, List<String>)
}
}
Bu hiç mantıklı değil! Burada bile iki farklı kullanım için çalışıyoruz değil, ve derleme değil! List<List<Integer>> lol
List<String> list
bir yapım da benzer bir derleme hatası veriyor! Benim denemelerle aslında, kodu derler tek yolu Eğer ilk argüman ** 35 açık bir türü (as seen on ideone.com):
import java.util.*;
public class LOLUnknowns1b {
static void probablyIllegal(List<List<?>> lol, List<?> list) {
lol.add(list); // this compiles!! how come???
}
public static void main(String[] args) {
List<String> list = null;
probablyIllegal(null, list); // compiles fine!
// throws NullPointerException at run-time
}
}
Soruları yani, LOLUnknowns1
, LOLUnknowns1a
LOLUnknowns1b
ile ilgili olarak:
- Ne tür argümanlar
probablyIllegal
kabul ediyor mu? lol.add(list);
hiç derlemek gerekir? Typesafe?- Bu derleyici bir hata ya da joker için yakalama dönüştürme kuralları yanlış mıyım?
Ek A: LOL Çift?
Herkes merak durumunda, bu güzel (as seen on ideone.com) derler:
import java.util.*;
public class DoubleLOL {
static void omg2xLOL(List<List<?>> lol1, List<List<?>> lol2) {
// compiles just fine!!!
lol1.addAll(lol2);
lol2.addAll(lol1);
}
}
Ek B: onlar gerçekten ne anlama geliyor?? iç İçe joker --?
Daha fazla araştırma belki de birden fazla joker karakter sorunu ile bir ilgisi yok, daha ziyade bir olduğunu gösteririç içe geçmişjoker karışıklık kaynağıdır.
import java.util.*;
public class IntoTheWild {
public static void main(String[] args) {
List<?> list = new ArrayList<String>(); // compiles fine!
List<List<?>> lol = new ArrayList<List<String>>(); // DOES NOT COMPILE!!!
// Type mismatch: cannot convert from
// ArrayList<List<String>> to List<List<?>>
}
}
List<List<String>>
List<List<?>>
bir değil, belki de öyle görünüyor. List<E>
herhangi bir ise aslında List<?>
, List<List<E>>
List<List<?>>
bir, herhangi bir(as seen on ideone.com)benzemiyor:
import java.util.*;
public class IntoTheWild2 {
static <E> List<?> makeItWild(List<E> list) {
return list; // compiles fine!
}
static <E> List<List<?>> makeItWildLOL(List<List<E>> lol) {
return lol; // DOES NOT COMPILE!!!
// Type mismatch: cannot convert from
// List<List<E>> to List<List<?>>
}
}
Sadece List<List<?>>
ne? yeni bir soru ortaya çıkıyor:
CEVAP
Ek B anlaşılacağı gibi, bu birden çok joker ile alakası yok, daha ziyade List<List<?>>
gerçekten ne anlama geldiğini bir yanlış anlama.
Hadi ilk Java jenerik değişmez olduğunu ne anlama geldiğini hatırlayalım:
Integer
Number
List<Integer>
DEĞİL56**- Bir 57**58**
Biz şimdi sadece iç içe geçmiş listesi durumumuz için de aynı argüman geçerli
List<String>
(captureable)List<?>
List<List<String>>
DEĞİL(captureable) 62**- 63**(captureable) 64**
Bu anlayışla, söz konusu parçacıklar tüm açıklanabilir. Karışıklık (yanlış) List<List<?>>
bir tür List<List<String>>
, List<List<Integer>>
, vb gibi türleri yakalayabilir inanarak doğar. BuDEĞİLdoğru.
O O List<List<?>>
bir:
- DEĞİLbazı bilinmeyen bir tür listeleri olan bir liste.
- ...
List<? extends List<?>>
bir olurdu
- ...
- Bunun yerine, listeleri olan bir listeHERHANGİ biryazın.
Parçacıkları
İşte yukarıdaki noktaları göstermek için bir parçacık:
List<List<?>> lolAny = new ArrayList<List<?>>();
lolAny.add(new ArrayList<Integer>());
lolAny.add(new ArrayList<String>());
// lolAny = new ArrayList<List<String>>(); // DOES NOT COMPILE!!
List<? extends List<?>> lolSome;
lolSome = new ArrayList<List<String>>();
lolSome = new ArrayList<List<Integer>>();
Daha fazla parçacıkları
Burada sınırlanan iç içe joker ile henüz başka bir örnek:
List<List<? extends Number>> lolAnyNum = new ArrayList<List<? extends Number>>();
lolAnyNum.add(new ArrayList<Integer>());
lolAnyNum.add(new ArrayList<Float>());
// lolAnyNum.add(new ArrayList<String>()); // DOES NOT COMPILE!!
// lolAnyNum = new ArrayList<List<Integer>>(); // DOES NOT COMPILE!!
List<? extends List<? extends Number>> lolSomeNum;
lolSomeNum = new ArrayList<List<Integer>>();
lolSomeNum = new ArrayList<List<Float>>();
// lolSomeNum = new ArrayList<List<String>>(); // DOES NOT COMPILE!!
Soruma geri dönelim
Parçacıkları geri soruda gitmek, beklendiği gibi aşağıdaki davranır (as seen on ideone.com):
public class LOLUnknowns1d {
static void nowDefinitelyIllegal(List<? extends List<?>> lol, List<?> list) {
lol.add(list); // DOES NOT COMPILE!!!
// The method add(capture#1-of ? extends List<?>) in the
// type List<capture#1-of ? extends List<?>> is not
// applicable for the arguments (List<capture#3-of ?>)
}
public static void main(String[] args) {
List<Object> list = null;
List<List<String>> lolString = null;
List<List<Integer>> lolInteger = null;
// these casts are valid
nowDefinitelyIllegal(lolString, list);
nowDefinitelyIllegal(lolInteger, list);
}
}
lol.add(list);
List<List<String>> lol
List<Object> list
olabilir, çünkü yasadışı. Biz soruna neden olan bir deyim açıklama aslında, kodu derler ve o main
ilk çağırma yaptığımız şey tam olarak bu.
Soru probablyIllegal
tüm yöntemleri, yasadışı değil. Tamamen yasal ve typesafe. Kesinlikle derleyici hata yok. Bunu yapmak gerekiyordu tam olarak ne olduğunu.
Referanslar
İlgili sorular
- Any simple way to explain why I cannot do
List<Animal> animals = new ArrayList<Dog>()
? - Java nested wildcard generic won’t compile
Ek: yakalama dönüşüm kuralları
(Bu yanıt, ilk Gözden Geçirme kadar getirildi; değişken, sabit tip için değerli bir ek.) 5.1.10 Capture Conversion
İzin verinGile genel türde bir beyan adınresmi parametreleri yazınBir
1...Bir sınırları ile ilgiliUn 1...U . Yakalama bir dönüşüm varG<Tn 1...T içinG<Lern> 1...S nerede, için1 <= <= n:n>
- EğerT
ben 79 ** formun joker tipi bir tartışma- EğerT
ben joker bir tip 80 ** formun argümanBben o zaman ...- EğerT
ben formun joker tipi bir değişken? super
Bben o zaman ...- Aksi takdirdeS
ben= T .ben Yakalama dönüşüm yinelemeli olarak uygulanmaz.
Bu bölümde özellikle yakalama dönüştürme (bu vesile ile . non-recursive uygulama açısından kafa karıştırıcı olabilir ^em>CCancak anahtartüm ?
CC; bulunduğu yere bağlıdır. Kural olarak özyinelemeli bir uygulama veya 3 2 kuralları geçerlidir 4, ama, ilgili, sonra diye bir şey yokB
İşte birkaç basit örnek ile çalışalım:
List<?>
List<String>
CC olabilir?
kural 1 CC
List<? extends Number>
List<Integer>
CC olabilir?
Kural 2 CC- Uygulama Kural 2,B
ben sadece 89**
- 90**DEĞİLCC
List<String>
?
Kural 2, ama zamanı hatası oluşur uyumsuz türleri nedeniyle derleme CC
Şimdi biraz iç içe deneyelim:
- 93**DEĞİLCC
List<List<String>>
- Kural 4 uygulanır ve CC özyinelemeli değildir,
?
DEĞİLCC
- Kural 4 uygulanır ve CC özyinelemeli değildir,
List<? extends List<?>>
List<List<String>>
CC olabilir- 98* *ilk Kural 2 CC
- Uygulama Kural 2,B
ben şimdiList<String>
CC olanList<?>
, bir - Her iki
?
CC
List<? extends List<? extends Number>>
List<List<Integer>>
CC olabilir?
ilk Kural 2 CC- Uygulama Kural 2,B
ben şimdiList<Integer>
CC olan ** 105, bir - Her iki
?
CC
- 108**DEĞİLCC
List<List<Integer>>
?
ilk Kural 2 CC- Uygulama Kural 2,B
ben şimdiList<Integer>
uygulandığında CC olabilir, ama derleme bir zaman verirList<? extends Number>
, bir hatadır - Her iki
?
CC
?
CC bazı ve diğerleri, aşağıdaki kuralları dikkate neden daha fazla göstermek için:DEĞİLdoğrudan joker bir tür oluşturmak. Yani, aşağıdaki gibi bir derleme zamanı hatası verir:
// WildSnippet1
new HashMap<?,?>(); // DOES NOT COMPILE!!!
new HashMap<List<?>, ?>(); // DOES NOT COMPILE!!!
new HashMap<?, Set<?>>(); // DOES NOT COMPILE!!!
Ancak, şu iyi derler:
// WildSnippet2
new HashMap<List<?>,Set<?>>(); // compiles fine!
new HashMap<Map<?,?>, Map<?,Map<?,?>>>(); // compiles fine!
WildSnippet2
derler nedeni yukarıda da belirtildiği gibi, ?
hiçbiri CC olmasıdır. WildSnippet1
, HashMap<K,V>
K
V
(veya ikisi birden) ya da new
ile doğrudan örnekleme geçersiz kılan CC.
Java Birden Fazla Sınıflar İle Joker K...
Birden fazla kısıtlamaları ile genel y...
Java nasıl bir yöntem birden fazla nes...
Birden fazla dosya üzerinde Javascript...
Genel tür parametre Java adlandırma (b...