2015-07-01 28 views
15

J. Bloch'un etkili Java'sını okuyorum ve şimdi diziler ve listeler bölümündeyim. İşte o sağlanan kontrolsüz döküm örneğidir:Denetlenmemiş yayınla ilgili sorun nedir?

interface Function<T> { 
    T apply(T arg1, T arg2); 
} 

public class Main{ 
    public static void main(String[] args){ 
     Function<String> f = null; 
     List<String> str = Arrays.asList("asd"); 
     //staff 
     reduce(str, f, ""); //E's deduced to String. Where is type-unsafe? 
    } 
    static <E> E reduce(List<E> list, Function<E> f, E initVal) { 
     E[] snapshot = (E[]) list.toArray(); // Unchecked cast 
     E result = initVal; 
     for (E e : snapshot) 
      result = f.apply(result, e); 
     return result; 
    } 
} 

O yöntem güvenli tip değildir ve kolayca ClassCastException alabilirsiniz söyledi. Ama nasıl göremiyorum. Tip-güvensiz olan, E tip değişkeni her zaman uygun türe indirgenecektir, bu yüzden sınıf-cast-exeption hakkında endişelenmiyoruz.

ClassCastException atma ile ilgili bir örnek vermediniz mi?

cevap

13

. Ayrıca, neredeyse her zaman Object[] türünde bir dizi döndürür. Böylece, bu dizinin sonraki kullanımına bağlı olarak, ClassCastException olabilir. İşte

public static void main(String[] args){ 
    List<String> str = Collections.singletonList("asd"); 
    String[] array = test(str); 
} 

static <E> E[] test(List<E> list) { 
    E[] snapshot = (E[]) list.toArray(); // Unchecked cast 
    return snapshot; 
} 

bu E[] dizi döndürür ve alıcı String[] dizi döndürülür bekler: Örneğin, şu kodu göz önünde bulundurun. Ama aslında Object[] dizisidir, bu nedenle main yönteminde ClassCastException yöntemini döndürdüğünüzde, döndürülen jenerik türün dolaylı olarak String[]'a gönderilmesi gerekir.

Kodunuzda dizinin güvenli bir şekilde kullanıldığından emin olabilirsiniz. Ancak derleyici bu analizi yapmak için yeterince akıllı değildir, bu yüzden sizi uyarır.

4

Burada kullandığınız list.toArray deyiminiz, List parametrized türündeki bir dizi tarafından parametrize edilmemiştir, bu nedenle Object[] değerini döndürür. Örneğin, List<String> str ile, aşağıdakileri yapabilirsiniz: String[] foo = str.toArray(new String[str.size()]); döküm olmadan.

Buradaki sorun, Java jeneriklerinin tasarımı nedeniyle, bir new E[]'u hiçbir zaman başlatamazsınız, dolayısıyla (E[])'a dökmeniz gerekir.

Bu görüntünün ClassCastException'u olduğu gibi göremiyorum.

Diğerlerinin de belirttiği gibi, "kozmetik" geçici çözümü, toArray çağrısından önce @SuppressWarnings("unchecked") eklemek ve bu uyarıyı engeller.

+2

__Ben bu kadarını bir ClassCastException atamadım, ne de yapabilirim, ama J. Bloch, bir tane almak için kolayca değiştirilebileceğini söyledi. –

3
sizin oyuncularla yanlış bir şey yok

ancak Java Generics ile:

list.toArray() tip E[] dizi dönecektir hiçbir derleme zamanı garantisi yok
static <E> E reduce(List<E> list, Function<E> f, E initVal) { 
    @SuppressWarnings({"unchecked"}) //nevermind 
    E[] snapshot = (E[]) list.toArray(); //Unchecked cast 
    E result = initVal; 
    for (E e : snapshot) 
     result = f.apply(result, e); 
    return result; 
} 
4

Nesne [] toArray() içinde (son elemana birinci) doğru sırayla bu liste tüm elemanları ihtiva eden bir dizi döner.

Bunu E [] inferring generics'e döküyoruz, böylece jvm, E'nin uyarı ne tür olacağını bilmediğinden cast'ın işaretli olmadığından.

Örneğin, E, String türüdür (kodunuzda olduğu gibi). Ve başka bir durum için Object [] to Dante [] to Object [] to Object [] 'e çevirmeye çalışıyoruz. Bu geçerlilik, jvm tarafından derleme/çalışma zamanında test edilemez.

public static void main(String[] args){ 
    List<String> str = Arrays.asList("asf"); 
    //staff 

    System.out.println(reduce(str, 2)); //E's deduced to String. Where is type-unsafe? 
} 
static <E, T> E reduce(List<E> list, T initVal) { 
    Object snapshot = list.size(); // Unchecked cast 
    return (E) snapshot; 
} 

Bu, sınıf dökümü istisnası oluşturacaktır.

İlgili konular