Java generics'in type parametresindeki soru işareti ne anlama geliyor?


216

Bu, Stanford Ayrıştırıcıya eşlik eden bazı örneklerden alınan küçük bir kod pasajıdır. Yaklaşık 4 yıldır Java'da geliştiriyorum, ancak bu kod tarzının ne göstereceği konusunda çok güçlü bir anlayışım olmadı.

List<? extends HasWord> wordList = toke.tokenize();

Kodun detayları konusunda endişelenmiyorum. Kafam karıştığım şey, genel ifadenin tam olarak İngilizce'ye iletmesi gereken şey.

Birisi bana bunu açıklayabilir mi?


Yanıtlar:


226
? extends HasWord

"Genişleyen bir sınıf / arabirim" anlamına gelir HasWord. Başka bir deyişle, HasWordkendisi veya çocukları ... temelde instanceof HasWordartı ile çalışacak her şey null.

Daha teknik terimlerle, sayfa 141'den başlayarak Etkili Java 3. Baskı'nın? extends HasWord 31. maddesinde yer alan sınırlı bir joker karakterdir . 2. Baskıdaki aynı bölüm PDF olarak çevrimiçi olarak mevcuttur ; sınırlı joker karakterler üzerindeki kısım sayfa 134'den başlayarak Madde 28'dir.

Güncelleme: Oracle bağlantısı bir süre önce kaldırdığından beri PDF bağlantısı güncellendi. Şimdi Londra Kraliçe Mary Üniversitesi Elektronik Mühendisliği ve Bilgisayar Bilimleri Okulu'nun ev sahipliği yaptığı kopyaya işaret ediyor.

Güncelleme 2: Neden joker karakterler kullanmak istediğinize dair biraz daha ayrıntıya girelim.

İmzası sizden geçmeyi bekleyen bir yöntem bildirirseniz, iletebileceğiniz List<HasWord>tek şey bir List<HasWord>.

Ancak, söz konusu imza olsaydı, bunun yerine List<? extends HasWord>bir pas geçebilirdiniz List<ChildOfHasWord>.

List<? extends HasWord>Ve arasında ince bir fark olduğunu unutmayın List<? super HasWord>. Joshua Bloch'un söylediği gibi: PECS = üretici-genişletiyor, tüketici-süper.

Bunun anlamı, yönteminizin verileri çıkardığı bir koleksiyondan geçiyorsanız (yani koleksiyon, yönteminizin kullanması için öğeler üretiyorsa) kullanmanızdır extends. Yönteminizin veri eklediği bir koleksiyondan geçiyorsanız (yani koleksiyon, yönteminizin oluşturduğu öğeleri tüketiyorsa) kullanmalıdır super.

Bu kafa karıştırıcı gelebilir. Ancak, görebiliyorum Listbireyin sort(Collections.sort iki-arg sürümü için sadece bir kısayol olan) komutu. Bir almak yerine, Comparator<T>aslında bir Comparator<? super T>. Bu durumda, Karşılaştırıcı ListListenin kendisini yeniden sıralamak için.


17
"instanceof ile çalışacak her şey" - artı null değerler. Herhangi bir denetim örneği için null değerlerin false değerini döndürdüğünü unutmayın.
Eyal Schneider

12
Arayüzleri unutmayın. ? bir sınıfı temsil etmek zorunda değil!
Mark Peters

9
List<HasWord>herhangi bir nesneyi içeren bir liste: tarif tam olarak ne xolduğu için x instanceof HasWordtrue döndürür ve null. Bunun için joker karakter gerekmez. Joker karakter, bu türün bir alt türü olduğu sürece, aslında başka bir türün listesi olabileceği anlamına gelir HasWord. (Geç yorum için özür dilerim.)
Paŭlo Ebermann

1
PDF bağlantısı çalışmıyor gibi görünüyor, ancak bu benim için yararlı oldu: docs.oracle.com/javase/tutorial/extra/generics/wildcards.html
user1338062

Bu garip, geçen sene @ user1338062 yayınlandığında ve PDF bağlantısının çalışmadığını bilmediğim bir mesaj almadım. Şimdi düzeltildi. Ayrıca kitabın kendisine bir bağlantı ekledim.
Powerlord

65

Soru işareti, 'herhangi bir tür' için bir göstergedir. ?yalnız demek

Herhangi bir tür Object(dahil Object)

yukarıdaki örneğiniz,

Uzanan ya da uygulama herhangi bir tür HasWord(dahil HasWordhalinde HasWordolmayan bir arka sınıfı)


2
peki ne public Set<Class<?>> getClasses()demek? Aradaki fark ne Set<Class>? Bakıyorum javax.ws.rs.core.Application.
tonoz

14

List<? extends HasWord>HasWord'u genişleten herhangi bir somut sınıfı kabul eder. Aşağıdaki dersleriniz varsa ...

public class A extends HasWord { .. }
public class B extends HasWord { .. }
public class C { .. }
public class D extends SomeOtherWord { .. }

... wordListSADECE As ya da Bs listesini ya da her ikisinin karışımını içerebilir, çünkü her iki sınıf da aynı ebeveyni genişletir null( ya da kontroller başarısız olursa HasWorld).


8
Sadece somut değil, soyut alt sınıflar.
bloparod

2
Somut ve soyut alt sınıfları değil, aynı zamanda alt arayüzleri Sadece: List<? extends Collection<String>> list = new ArrayList<List<String>>();.
Mark Peters

2
Bunun için joker karakterlere ihtiyacınız yok, aslında: List<HasWord>bunun için de iyi. Buradaki nokta, bu değişkenin a List<A>ya List<B>da a içerebilir List<HasWord>.
Paŭlo Ebermann

12

Belki de yapmacık bir “gerçek dünya” örneği yardımcı olacaktır.

İş yerimde farklı lezzetlerden gelen çöp kutuları var. Tüm kutular çöp içerir, ancak bazı kutular uzmandır ve her türlü çöpü almaz. Bizde var Bin<CupRubbish>ve Bin<RecylcableRubbish>. Tip sisteminin HalfEatenSandwichRubbishbu tiplerden herhangi birine giremediğimden emin olması gerekiyor , ancak genel bir çöp kutusuna girebilir Bin<Rubbish>. Eğer uzmanlaşabilecek bir Binşeyden bahsetmek isteseydim , Rubbishbu yüzden uyumsuz çöplere giremem, o zaman olurdu Bin<? extends Rubbish>.

(Not: ? extendssalt okunur değildir. Örneğin, uygun önlemlerle, bilinmeyen bir uzmanlık kutusundan bir parça çöp alabilir ve daha sonra farklı bir yere koyabilirim.)

Bunun ne kadar yardımcı olduğuna emin değilim. Polimorfizm varlığında işaretçi-işaretçi tam olarak açık değildir.


5

İngilizcede:

Bu bir var Listsınıfını genişleten bir tür HasWordde dahil olmak üzereHasWord

Genel ?olarak jenerikte herhangi bir sınıf anlamına gelir. Ve extends SomeClassbu nesnenin genişletilmesi SomeClass(veya bu sınıf olması) gerektiğini belirtir.


1
Aslında, sınıf yerine yazın . Bu arayüzler için de geçerlidir.
Paŭlo Ebermann

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.