2010-05-02 26 views
13

Bir aralıktaki tüm öğeleri yazdırmak için aşağıdaki yaklaşımlar arasında pratik bir fark var mı? her şey zaten bir nesne olduğunu -Joker kodları ve jenerik yöntemler

public static void printA(Iterable<?> range) 
{ 
    for (Object o : range) 
    { 
     System.out.println(o); 
    } 
} 

public static <T> void printB(Iterable<T> range) 
{ 
    for (T x : range) 
    { 
     System.out.println(x); 
    } 
} 

Görünüşe göre, printB ek Nesne için döküm checked gerektirir bana oldukça saçma bir tavır sergileyen (hat 16 bakınız)?

public static void printA(java.lang.Iterable); 
    Code: 
    0: aload_0 
    1: invokeinterface #18, 1; //InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator; 
    6: astore_2 
    7: goto 24 
    10: aload_2 
    11: invokeinterface #24, 1; //InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object; 
    16: astore_1 
    17: getstatic #30; //Field java/lang/System.out:Ljava/io/PrintStream; 
    20: aload_1 
    21: invokevirtual #36; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V 
    24: aload_2 
    25: invokeinterface #42, 1; //InterfaceMethod java/util/Iterator.hasNext:()Z 
    30: ifne 10 
    33: return 

public static void printB(java.lang.Iterable); 
    Code: 
    0: aload_0 
    1: invokeinterface #18, 1; //InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator; 
    6: astore_2 
    7: goto 27 
    10: aload_2 
    11: invokeinterface #24, 1; //InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object; 
    16: checkcast #3; //class java/lang/Object 
    19: astore_1 
    20: getstatic #30; //Field java/lang/System.out:Ljava/io/PrintStream; 
    23: aload_1 
    24: invokevirtual #36; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V 
    27: aload_2 
    28: invokeinterface #42, 1; //InterfaceMethod java/util/Iterator.hasNext:()Z 
    33: ifne 10 
    36: return 

cevap

7

Örneğinizde, jenerik tür, imzanın tam olarak numaralı noktasında kullanılır. Bu senaryoda, T türünde numaralı arayanın joker karakteri 'a göre hiçbir avantajı yoktur. Örneğinizde, bu yöntemin uygulayıcısı için de türün avantajı yoktur.

Arayan için daha kolay bir joker karakterini buluyorum, çünkü açıkça yazıyor " türünü umursamıyorum".

Örneğinizde, checkcast gerçekten gereksizdir. T extends Number'da olduğu gibi T sınırlanmışsa gerekli olacaktır. Daha sonra Number için bir kontrol noktası gereklidir, çünkü x yerel değişkeni Number türünde olacaktır, ancak Iterator.next() yöntemi hala Object değerini döndürür. Java derleyicisi dökümünü optimize etmeyi tercih etmiyor gibi görünüyor. JIT muhtemelen çalışma zamanında bunu yapacaktır.

GÜNCELLEME:

genel tür Cletus'un yanıtında olduğu gibi, çeşitli noktalarda kullanılırsa, bir genel tür T, ya da başka derleyici kullanmaktan başka seçenek var parametre türü arasında bir bağlantı görmüyor/return tipi (herhangi bir iki joker karakter, derleyici için farklıdır).

Sınırda bir örnek, imzanın yalnızca bir noktada yazdığı bir durumdur, ancak uygulamanın joker karakter yerine genel bir tür olması gerekir. void swap(List<T> list, int a, int b) yöntemini düşünün. Öğeleri listeden çıkarmalı ve bunları geri yüklemelidir. IIRC, Etkili Java, joker karakterli bir genel yöntem ve gerçek uygulamayı içeren bir türden bir iç yardımcı yöntem kullanılmasını önerir. Bu şekilde, kullanıcı basit bir API alır ve uygulayıcı hala tip güvenliğine sahiptir.

public void swap(List<?> list, int a, int b){ 
    swapHelper(list, a, b); 
} 
private <T> void swapHelper(List<T> list, int a, int b){ 
    ... 
} 
+0

Katılıyorum: * bu durumda * joker sürüm daha iyidir. – Jorn

2

İkincisi daha esnektir. Daha iyi bir örnek: Bu tür hakkında bir şey söylüyor. Sizin için yararlı olup olmama, işlevin ne işe yaradığına bağlıdır.

ikinci yöntemden şey dönmek istediğinizde yararlılığını kanıtlamıştır:

public static <T> List<T> reverse(List<T> list) { 
    for (int i=0; i<n/2; i++) { 
    T value = list.get(i); 
    list.set(i, list.get(list.size() - i - 1)); 
    list.set(list.size() - i = 1, value); 
    } 
    return list; 
} 

Bu diziyi ama noktasını kopyalamak için daha iyi bir örnek muhtemelen var gerçekten List<?> yukarıda yapamaz kalır .

+0

Bunu anlamıyorum. Anlayabildiğim kadarıyla, iki form tam olarak aynı bağlamlarda kullanılabilir ve biri diğerinden daha fazla veya daha az tip bir güvenlik vermez. Bir şey mi eksik? –

+1

@Marcelo Kullanıyorsanız?sürüm, çağrı yönteminin bir List'e geri döneceğini ve bu Listenin kendisini Listesinin bir Listesine göndermesi gerektiğini belirtir. Derleyici, uygulamanın aslında bir Liste ürettiğini kontrol edemediği için biraz güvensizdir. Sözleşme (? Ile), bir Listenin iade edileceğini belirtir ve bu bir Liste değilse bile geçerlidir. T versiyonu böylece, derleyicinin dönüş türünü kontrol etmesine ve çağrı yönteminin daha güvenli olmasına izin verir. – extraneon

+0

Evet, ancak T argüman listesinde tek bir yerde (OP'nin örneğindeki gibi) göründüğünde, joker karaktere dönüştürülebilir. Bu örnek farklıdır (T, dönüş dahil olmak üzere iki yerde görünür). – newacct

0

Gerçekten değil. Ortaya çıkan bayt kodu hemen hemen aynı olmalıdır.

+0

Değil, benim düzenlememi gör. – fredoverflow

+0

Ah, evet. Yani '' sürümü aslında içeriğin doğru türden olduğunu denetler ve bu nedenle "Geçilmez ", "T" olmayan bir şey içeriyorsa başarısız olabilir. Cevabımı biraz yumuşattım. –

+0

@Marcello: Hayır, yinelenebilir bir 'un T olmayan bir şey içerip içermediğini kontrol etmez. Sadece Object'e gönderilemeyen bir şey içerip içermediğini kontrol eder. Ancak jenerikler Java çok aptalca uygulanmış olduğunu varsayalım ki bu sadece bir başka kalıntıdır ... – Foxfire