2016-03-21 32 views
15

Varargs kullandığınızda, sonuçta oluşan dizinin bileşen türü nasıl belirlenir?Varargs dizisi için bileşen türü nasıl belirlenir?

Örneğin, bu program true'u yazdırmayı garanti ediyor mu veya davranış teknik olarak belirtilmemiş mi?

public static void main(String[] args) { 
    foo("", 0); 
} 

static <T> void foo(T... arr) { 
    System.out.println(arr.getClass() == Serializable[].class); 
} 
+2

Buradaki cevabın burada "denediğim her derleyici ile her zaman en azından bazı uyumsuzluklara sahip olan, anlaşılmaz karmaşıklıklarındaki tüm tür çıkarım kuralları" olmasını beklerim. –

+1

Muhtemelen: http://docs.oracle.com/javase/specs/jls/se8/html/jls-18.html#jls-18.5.1 ve takip ediyor. – assylias

cevap

1

Eh, bu konuda% 100 emin değilim, ama bu varargs ile ilgisi yoktur düşünüyorum, ama daha dinamik bağlama, jenerik ve tip silme gibi.

"Java'daki diziler değişkendir, ancak jenerikler değil. Başka bir deyişle, String [] bir Object [] alt dizisidir, ancak Stack Stack'in bir alt türü değildir."

Kaynak: http://algs4.cs.princeton.edu/13stacks/

Yani soruyu cevaplamak için, bu davranış belgelenmiş ve beklenen belirtilir. Kitapta

: 'Etkili Java' Joshua Bloch şöyle açıklıyor:

Diziler iki önemli noktada jenerik türlerinden farklıdır. İlk olarak, diziler kovaryanttır. Bu korkutucu-iskandil kelimesi, eğer Sub bir Süper alt-tipi ise, o zaman Sub [] dizi tipi Super [] 'un bir alt-tipi anlamına gelir. Aksine, jenerikler değişmezdir: herhangi bir iki tip için Type1 ve Type2, List <Type1>, ne tür bir alt tip ne de bir üst tip olan List < [JLS, 4.10; Naftalin07, 2.5]. Bunun jeneriklerin eksik olduğu anlamına geleceğini düşünebilirsiniz, ancak tartışmasız eksik olan dizilerdir.

Ve neden dizilerden bahsedebilirim? Eh, çünkü varargs en sonunda diziler haline gelecek.

"Geçmiş sürümlerde, rasgele bir değer sayısı alan bir yöntem, bir dizi oluşturmanızı ve bu yöntemi çağırmadan önce değerleri diziye koymanızı gerektiriyordu."

"Birden çok bağımsız değişkenin bir dizide geçirilmesi gerektiği doğrudur, ancak varargs özelliği işlemi otomatik hale getirir ve gizler."

Kaynak: Bu cevap% 100 Aradığınız cevabı olmayabilir, ama belki yardımcı olur https://docs.oracle.com/javase/8/docs/technotes/guides/language/varargs.html

2

. Genel olarak, arr.getClass() bazı dizi sınıflarını (en genel Object[].class, ancak Integer[].class, Number[].class, hatta Serializable[].class olabilir - normalde tüm öğelerin en özel türü olabilir, ancak ben buna güvenmezdim. szalik cevap). Dizideki tüm sınıfların Serializable örneğinin olduğundan emin olmak istiyorsanız, her bir öğeyi kontrol etmeniz gerekir (btw.sunulan uygulama) null değeri desteklemez: Btw

:

static <T> void foo(T... arr) { 
    System.out.println(Stream.of(arr) 
      .filter(e -> !Serializable.class.isInstance(e.getClass())) 
      .findFirst() 
      .orElse(null) == null); 
} 

Sen de bakabilirsiniz isteyebilirsiniz.

Eh, bu konuda emin% 100 değilim, ama bu varargs ile ilgisi yoktur düşünüyorum, ama daha dinamik bağlama, jenerik ve tip silme gibi: Kaptan Fogetti görüşüne katılıyorum.

NOT:

Sadece foo uygulama bazı örnekler:

  • foo(1, 2)Number[].class
  • foo ("", 1)Serializable[].class olacağını Integer[].class
  • foo(1, 2.0) olurdu olurdu
  • foo(null, 2)
  • Integer[].class
  • foo("", new Object())Object[].class
1

O varargs ilgili değil ama jenerik hakkında daha fazla olacağını olurdu.
Derleme sırasında genel bilgiler kayboluyor. Varargs parametreniz derleyici tarafından bir diziye dönüştürülür. Bu yüzden JVM, türle ilgili değil, ancak derleyicinin kararını verir. kararın

public static void main(String[] args) { 
    foo(new Serializable[]{"", Integer.valueOf(0)}); 
} 

algoritma oldukça uzundur ama burada bu konuda bilgi edinebilir:

Kodunuz folows gibi bir baytkoduna derlenmektedir., https://docs.oracle.com/javase/tutorial/java/generics/genTypeInference.html

3

Bu kodu koştum ve çıkış Eğer

Dürüst olmak gerekirse bu sihirli arkasındaki nedenleri bilmiyorum (sınıflar farklı hiyerarşi dallarda birden fazla ortak atadan geldiği en az ise) hiçbir garanti var söyler ama sadece bir yorum

import java.util.*; 
import java.lang.*; 
import java.io.*; 

class Ideone 
{ 

    interface A{} 
    interface B{} 
    class AB implements A, B {} 
    class BA implements A, B {} 

    public static void main (String[] args) throws java.lang.Exception 
    { 
     foo(new AB(), new BA()); 
     foo2(new AB(), new BA()); 
    } 

    static <T> void foo(T... arr) { 
     System.out.println(arr.getClass() == A[].class); 
    } 

    static <T> void foo2(T... arr) { 
     System.out.println(arr.getClass() == B[].class); 
    } 
} 

çıkış

true 
false 
olarak gönderemedik

Daha garip şeyler:

interface B Eğer interface A önce ilan edilir, sonuç tam tersidir:

false 
true 

implements blokta yöntem çağrısı, yöntemi beyanı düzen ve arayüzleri sırasına göre argümanlar sırasını değiştirme yapar benim için etki yapmam (1.8.0_51).

İlgili konular