Soru Java uzun parametre kabul etmiyorsa neden uzun parametreyi yüzdürme / iki katına çıkarır?


İşte bir SSCCE açıklanan (IMHO, garip) davranışı gösteren:

public class Test {

   public static void print(int param) {
       System.out.println("int");
   }

   public static void print(float param) {
       System.out.println("float");
   }

   public static void print(Long param) { //<--Wrapper type
       System.out.println("Long");
   }
   public static void main(String[] args) {
       long param = 100L;
       print(param);  // output == float
   }
} 

Java bunu neden yapıyor?


31
2018-01-27 17:15


Menşei




Cevaplar:


Java Dil Özellikleri bu konuda oldukça açık (vurgu benim):

15.12.2 Derleme Zamanı Adım 2: Yöntem İmzasını Belirleme

[...]

  1. İlk aşama (§15.12.2.2) aşırı yük çözünürlüğü gerçekleştirir izinsiz   boks veya kutu açma dönüşüm [...] Bu aşamada uygulanabilir bir yöntem bulunmazsa işlem devam eder   ikinci aşamaya. [...]

  2. İkinci aşamada (§15.12.2.3) aşırı yük çözünürlüğü uygulanır. izin   boks ve unboxing [...]

  3. Üçüncü aşama (§15.12.2.4) aşırı yüklenmenin değişkenle birleştirilmesine izin verir.   aritma yöntemleri, boks ve kutuklama.

Yani, sadece ilk adımda print(int) ve print(float) uygun olabilir. İkincisi eşleşir ve daha fazla soruşturma yapılmaz.


Bu tür kuralların nedeni de JLS'de açıklanmıştır:

Bu, Java SE 5'ten önce Java programlama dilinde geçerli olan aramaların, değişken aritma yöntemleri, örtük boks ve / veya kutunun çıkarılmasının sonucu olarak belirsiz kabul edilmediğini garanti eder.

Düşünün ki Test sınıf, Java 1.4'e (otomatik kutudan önce) karşı derlenmiştir. Bu durumda açık: print(float) seçilmeli (neden anlaştığımızı varsayarsak long için float güvenli kabul edilir ve örtülü olabilir ...) olarak print(Long) tamamen uyumsuz long argüman.

Daha sonra aynı kodu Java 5+ ile derlersiniz. Derleyici şunları yapabilir:

  • seçmek print(Long) daha fazlası "açık"Bu bağlamda. Böylece Java 5'e yükselttikten sonra programınız farklı davranıyor ...

  • çağrı belirsiz olduğu için derleme hatası verir. Bu nedenle, daha önce doğru kod, Java 5 altında artık derlenmemektedir (ki bu AFAIR asla böyle değildir).

  • ... veya eski semantikleri koruyun ve Java 1.4 ile aynı yöntemi çağırın.

Şimdi neden anlamanız gerekir print(float) kullanılır - çünkü Java 1.4 altında seçilecekti. Ve Java geriye dönük uyumlu olmalıdır.


31
2018-01-27 17:20



İlk aşırı yükü, son ikiden daha iyi bir eşleşme olarak görmüyorum (ilk aşırı yük, uygun aşağı akış ile gerçekleştirilebilir) - John Dvorak
FYI çıkarırsanız float örnek aşırı, seçer Long üzerinde int: ideone.com/x6HZ1Q - Paul Bellora
@PaulBellora: Bu ilginç gözlem için teşekkürler, yukarıdaki kuralların işe yaradığını kanıtlıyor. print(int) tek başına tamamen uyumsuz long (kaldırmayı deneyin print(Long) - derleme hatası), böylece derleyici aşama 2'ye geçer. - Tomasz Nurkiewicz
+1 Bunun yaptıklarını belirtiyor gibi görünüyor. Açıklayabilir misin niye ya sizin düşüncenizde var mı? - Peter Lawrey
@PeterLawrey: geriye dönük uyumluluğu doğru bir şekilde işaret ettiniz, biraz daha kapsamlı bir açıklama ekledim, teşekkürler! - Tomasz Nurkiewicz


Seçtiği nedeni float üzerinde Long Otomatik kutulama daha sonra eklenmiş ve geriye dönük uyumluluk nedenleriyle aynı çağrıyı her zaman yapması gerekecek.


12
2018-01-27 17:51





Tomasz Nurkiewicz şartnamenin ilgili bölümüne işaret ediyor (Java SE 7 JLS'de 15.12.2), ama neden böyle? Geriye dönük uyumluluk için 1.4 ve önceki sürümleri hedefleyen kaynak kodu, aynı aşırı yüklenmiş yöntemi çağırmaya devam etmelidir. Bu nedenle, 1.5'in özellikleri göz ardı edilmeli ve yalnızca kodun başka bir şekilde derlenmemesi durumunda otomatik kutu düşünülmelidir.

Neden dönüşüm hakkında long için float örtük olabilir - bu sadece şüpheli bir tasarım seçimidir.


7
2018-01-27 17:35



Temel olarak sorunlu tasarım tercihi, aşırı yüklenmiş bir yöntemin veya operatörün birden fazla türü alabileceği durumlarda bile, mevcut olan örtülü dönüşümlerin yasal olması gerektiğine (tanı koymadan) karar vermekti. Bu tasarım tercihi, Java için aptalca bir döküm gerektiren float f=(float)(1.0/10.0);ama değil double d=1.0f/10.0f;ne için if (f==d).... İlk ifadedeki oyuncu okunabilirliği arttırmak veya potansiyel bir hataya dikkat çekmek için hiçbir şey yapmaz; aksine, bir kod incelemesi yapıyordum ve kod sözde anlambilimsel anlamlara sahip olmak ... - supercat
... ikincisi, ikinci ifadenin double f=(double)(float)(1.0f/10.0f) and the third as eğer ((çift) f == d), since in the former case the *intended* meaning could likely have been to perform the division as double` (ve bir oyuncuya doubletek başına, bunu açıklığa kavuşturmazdı); İkinci durumda, bir yazım olmadan, karşılaştırmanın test edip etmeyeceğini f kopyalandığında tutulacak değeri tutar d, Ya da d kopyalandığında tutulacak değeri tutar f. Aşırı yükleme ile örtülü dönüşümlerin kullanımını kısıtlama ... - supercat
... derleyicinin, mantıklı olduklarında örtük dönüşümler yapmasına izin vermezdi ve yapamadıkları yerlerde squawk yapardı. Bir kaynak dosyanın tamamı veya bir kısmı için seçenekler ayarlanabiliyorsa, davranış uyumsuzluk olmadan geliştirilebilir düşünüyorum. - supercat


Belgelere bakın

Bölüm 5. Dönüşümler ve Promosyonlar

5.1.2. İlkel Dönüşümün Genişletilmesi

İlkel tiplerdeki 19 spesifik dönüşümün genişlemesi denir   ilkel dönüşümler:

  • kısa, int, uzun, kayan nokta veya çifte bayt
  • int, long, float veya double'a kısa
  • int, uzun, kayan nokta veya çifte char
  • int uzun, kayan veya çift
  • yüzdürmek veya çiftlemek uzun
  • ikiye kayar

Yani dönüşüm formu long için float kurallarla birlikte.


4
2018-01-27 17:22