2014-04-11 31 views
22
public class Primitive { 
    void m(Number b, Number ... a) {} // widening, autoboxing->widening->varargs 

    void m(byte b, Number ... a) {} // unboxing, autoboxing->widening->varargs 

    public static void main(String[] args) { 
     Byte b = 12; 
     Primitive obj = new Primitive(); 
     obj.m(b, 23); 
    } 
} 

Zaten çoktan arama önceliğinin kutudan daha yüksek olduğunu buldum ve bulunduğumdan, yukarıdaki yöntem çağırma işleminde, ikinci yöntem her ikisi için aynı olduğundan, ilk yöntem çağrılmalıydı. Ama bu gerçekleşmez. Açıklayabilir misin?Bu yöntem neden aşırı belirsiz oluyor?

+1

Benim için derler - hangi derleyiciyi kullanıyorsunuz? (Ve hangi sürüm?) –

+0

Bu önceliklendirme bağımsız adımlarla gerçekleşir. Önce direk, sonra genişleterek, sonra kutuyu aç. –

+0

jdk kullanıyorum 1.6 – Aman

cevap

7

JDK 1.5, 1.6 ve 1.7'de derleme yapamaz, ancak JDK 1.8'de çalışır.

Güncelleme: O versiyonları aslında bir böcek olan ilk JDK8 ile çalıştı gerçeği gibi görünüyor: Bu JDK 1.8.0_05 çalışmış, ancak this question göre ve medvedev1088 bu kod olacak tarafından cevap hayır artık bu sabit olduğunu bir hata olduğunu sanmıyorum JLS

uygun davranıştır ki, 1.8.0_25 yılında derlemek. Bunun yerine, Java 8'deki lambda ifadeleri için yöntem çağırma mekanizmalarıyla ilgili değişikliklerin bir etkisi.

Çoğu kişi, "Yöntem Çağırma İfadeleri" hakkındaki bölümün, en karmaşık anlaşılmaz kısım olduğunu kabul ederdi. Java Dil Özellikleri. Ve muhtemelen bu bölümü çapraz kontrol ve doğrulama ile ilgili tüm mühendisler ekibi var. Yani herhangi bir ifade veya herhangi bir girişimde bulunulması çok büyük bir tuzla alınmalıdır. (Bahsi geçen mühendislerden gelse bile). JLS 7

  • Method Invocation Expressions bölümünde yaklaşık

    • Method Invocation Expressions düşünüldüğünde

      : Ama diğerleri daha fazla analiz için anlamlara gelebilir ilgili bölümlerine üzerinden en az bedene, bir deneyin vereceğiz JLS 8

    ve her iki yöntem de "Potansiyel uygulanabilir yöntemler" olduğu göz önüne alındığında (JLS7/JLS8), daha sonra, ilgili alt bölüm yaklaşık bir

    olan JLS 7 için JLS8
  • içinde

  • Phase 3: Identify Methods Applicable by Variable Arity Invocation JLS7
  • içinde
    • Phase 3: Identify Applicable Variable Arity Methods, bu yöntem, m, ancak ve ancak tüm halinde bir uygulanabilir değişken Arity yöntemi olan

      belirtmektedir Aşağıdaki koşullar geçerlidir:

      • 1 = i < n için, ei, Ai'nin türü, Si'ye metot çağırma dönüşümü ile dönüştürülebilir.
      • ...

    • (diğer koşullar, örneğin burada alakalı olmayan çağırma formlarına kastediyoruzGerçekten varargs ya da örneğin atfen jenerik içeren çağırmaları)

      kullanımı yürütme: b yöntemi ile ilgili resmi yöntemi parametre dönüştürülebilir zaman bir yöntem olup, gerçek bağımsız değişken ifade tip Byte arasında b için geçerlidir çağırma dönüşümü. JLS7 ile ilgili olarak Method Invocation Conversion karşılık gelen bölümüne göre, aşağıdaki dönüştürme izin verilir:

      • bir kimlik dönüşümü (§5.1.1)
      • genişleyen ilkel dönüşümü (§5.1.2)
      • genişleyen bir referans dönüşüm (§5.1.5)
      • boks dönüşümü (§5.1.7) isteğe bağlı olarak bir referans dönüşüm
      • bir kutudan çıkarma dönüşümü (§5.1.8) isteğe bağlı olarak genişleyen bir ilkel dönüştürülmesi takip genişleyen takip eder. Bu spesifikasyona göre uygulanabilir iki yöntem vardır Açıkçası

      :

      • m(Number b, Number ... a) referans dönüşüm
      • m(byte b, Number ... a) genişleyen yoluyla uygulanabilir kutudan çıkarma dönüşüm yoluyla uygulanabilir

      "ifadesinden bahsettiniz" ... genişleyen önceliğin daha yüksek olduğunu buldu bir "unboxing", ancak bu burada geçerli değildir: Yukarıda listelenen koşullar herhangi bir "öncelik" içermez. Farklı seçenekler olarak listeleniyorlar. İlk yöntem void m(Byte b, Number ... a) olsa bile, "kimlik dönüşümü" uygulanabilir, ancak yine de yalnızca bir olası dönüşüm olarak sayılır ve belirsizlik nedeniyle bir hata yöntemine neden olur. o JDK7 ile değil işi neden yaptığını


      Yani, bildiğim kadarıyla anlamış gibi bu açıklıyor. 'un neden JDK8 ile çalıştığı'un neden detaylandırıldığını anlamadım. Ancak değişken Arity yöntemleri uygulanabilirliği tanımı Identify Methods Applicable by Variable Arity Invocation in JLS 8 içinde Slighly değiştirildi:

      m, genel yöntem değilse, o zaman m değişkeni Arity çağırma ile uygulanabilir, eğer 1 ≤ i ei birinde uyumlu, k ≤ Ti veya ei ile gevşek bir isteme bağlamı uygulanabilirlik için uygun değildir (§15.12.2.2). ,

      (Ben derin "gevşek çağırma bağlamlarda" ve bölüm §15.12.2.2 tanımları içine henüz dalış yoktu, ama bu burada önemli bir fark gibi görünüyor)


      bir kenara "... genişleme önceliğinin kutusundan daha yüksek olduğunu buldu" ifadesini kullanan bir kez daha: Bu varargs içermeyen yöntemler için geçerlidir (ve hiç yöntem çağırma dönüştürme gerektirmez). Örneğinizde varags'ları dışladıysanız, eşleştirme yöntemini bulma işlemi Phase 1: Identify Matching Arity Methods Applicable by Subtyping'da başlayacaktır.m(Number b) yöntemi Number'un bir alt türü olan Byte nedeniyle Byte b parametresi için zaten geçerli olabilir. Phase 2: Identify Matching Arity Methods Applicable by Method Invocation Conversion'a gitmek için bir sebep olmayacaktı. Bu aşamada, Byte'dan byte'a kutu açma yoluyla yöntem çağırma dönüşümü uygulanacaktır, ancak bu aşamaya asla ulaşılamamıştır.

    +2

    İşte benzer bir soru http://stackoverflow.com/questions/30130720/method-overload-ambiguity-with-java-8-ternary-conditional-and-unboxed-primitives/30137369#30137369 – medvedev1088

    +1

    @ medvedev1088 Hala çalışmadım "Çağırma bağlamları" vb. ile ilgili güncellemelerin ayrıntıları. Fakat şimdi, bağlantıya bağladığınız soruya (ve cevabınıza) göre, ** buradaki kodun ** işte olduğu gibi ** JDK8 ile daha önceki JDK8 sürümlerinde bir hata oldu ve bu hata 8-25 sürümünde düzeltildi - kabul ediyor musunuz? – Marco13

    +1

    Evet kabul ediyorum. Sadece JDK 1.8.0_25 üzerinde test edildi ve derleme yapmıyor. Ve derleyicinin hangi yöntemin daha spesifik olduğunu belirlemesi için bir yol olmadığı için JLS'ye göre yapılmamalıdır. Ayrıca önemli bir soruyu da gündeme getiriyor: JLS'nin geliştirilip geliştirilmeyeceği ve nasıl geliştirilebileceği. Bazı derleyici hataları, bağlandığım sorudaki gibi inandırıcıdır. Ne düşünüyorsun? – medvedev1088