SORU
23 AĞUSTOS 2010, PAZARTESİ


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
23 AĞUSTOS 2010, PAZARTESİ


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:

  1. Integer Number
  2. List<Integer>DEĞİL56**
  3. Bir 57**58**

Biz şimdi sadece iç içe geçmiş listesi durumumuz için de aynı argüman geçerli(daha ayrıntılı bilgi için ek):

  1. List<String> (captureable) List<?>
  2. List<List<String>>DEĞİL(captureable) 62**
  3. 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


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ınBir1...Birnsınırları ile ilgiliU1...Un. Yakalama bir dönüşüm varG<T1...Tn>içinG<Ler1...Sn>nerede, için1 <= <= n:

  1. EğerTben79 ** formun joker tipi bir tartışma
  2. EğerTbenjoker bir tip 80 ** formun argümanBbeno zaman ...
  3. EğerTbenformun joker tipi bir değişken ? superBbeno zaman ...
  4. Aksi takdirdeSben= Tben.

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 yokBbenbir CC olabilir kendisi.

İş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,Bbensadece 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
  • List<? extends List<?>> List<List<String>>CC olabilir
    • 98* *ilk Kural 2 CC
    • Uygulama Kural 2,Bbenşimdi List<String> CC olan List<?>, bir
    • Her iki ? CC
  • List<? extends List<? extends Number>> List<List<Integer>>CC olabilir
    • ? ilk Kural 2 CC
    • Uygulama Kural 2,Bbenşimdi List<Integer> CC olan ** 105, bir
    • Her iki ? CC
  • 108**DEĞİLCC List<List<Integer>>
    • ? ilk Kural 2 CC
    • Uygulama Kural 2,Bbenşimdi List<Integer> uygulandığında CC olabilir, ama derleme bir zaman verir List<? 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.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Dave Wallace

    Dave Wallace

    27 Kasım 2007
  • EEVblog

    EEVblog

    4 NİSAN 2009
  • Crossover

    Crossover

    18 HAZİRAN 2007