Javac neden diğerlerine değil bazı imkansız kalıplara izin veriyor?


52

Bir döküm denerseniz Stringbir etmek java.util.Date, Java derleyici hatası yakalar. Peki derleyici aşağıdakileri neden hata olarak işaretlemiyor?

List<String> strList = new ArrayList<>();                                                                      
Date d = (Date) strList;

Tabii ki, JVM bir ClassCastExceptionçalışma zamanında atar , ancak derleyici bunu işaretlemez.

Davranış javac 1.8.0_212 ve 11.0.2 ile aynıdır.


2
ListBurada özel bir şey yok. Date d = (Date) new Object();
Elliott Frisch

1
Son zamanlarda bir arduino ile oynuyorum. Herhangi bir oyuncu kadrosunu mutlu bir şekilde kabul etmeyen bir derleyiciyi çok sevdim ve sonra bunları tamamen öngörülemeyen sonuçlarla yaptı. Tam sayı dizesi? Tabi ki! Tam sayıya iki katı mı? Evet efendim! Boole dizesi? En azından bu çoğunlukla yanlış olur ...
Stian Yttervik

@ElliottFrisch: Tarih ve Nesne arasında bariz bir miras ilişkisi var, ancak Tarih ve Liste arasında bir ilişki yok. Bu yüzden derleyicinin bu kadroyu işaretlemesini bekledim, aynı şekilde String'den Date'e bir kadroyu işaretleyecekti. Ancak Zabuza'nın mükemmel cevabında açıkladığı gibi, List bir arayüzdür, bu yüzden strListList'i uygulayan bir sınıf örneği olsaydı oyuncu kadrosu yasal olurdu .
Mike Woinoski

Bu sık sık tekrarlanan bir soru ve eminim ki bunun birden fazla kopyasını gördüm. Temel olarak şiddetle ilgili
Hulk

1
@StianYttervik -fpermissive bunu yapıyor. Derleyici uyarılarını açın.
bobsburner

Yanıtlar:


86

Dökme olduğu teknik olarak mümkün. Javac tarafından durumunuzda böyle olmadığı kolayca kanıtlanamaz ve JLS aslında bunu geçerli bir Java programı olarak tanımlar, bu nedenle bir hatayı işaretlemek yanlış olur.

Çünkü Listbir arayüzdür. Yani Dateaslında burada Listolduğu gibi gizlenmiş bir alt sınıf olabilir List- ve sonra döküm Datemükemmel tamam olacaktır. Örneğin:

public class SneakyListDate extends Date implements List<Foo> {
    ...
}

Ve sonra:

List<Foo> list = new SneakyListDate();
Date date = (Date) list; // This one is valid, compiles and runs just fine

Bu tür bir senaryoyu saptamak her zaman mümkün olmayabilir, çünkü örneğin örneğin bir yöntemden geliyorsa çalışma zamanı bilgileri gerektirecektir. Ve olsa bile, derleyici için çok daha fazla çaba gerektirecektir. Derleyici, sınıf ağacının hiç eşleşememesi nedeniyle kesinlikle imkansız olan dökümleri önler. Görüldüğü gibi burada durum böyle değil.

JLS kodunuzun geçerli bir Java programı olmasını gerektirdiğini unutmayın. In 5.1.6.1. İzin verilen Daralma Referans Dönüşümü :

Bir daraltma referans dönüşüm referans türünden mevcut Sbaşvuru tipi için T, eğer tüm aşağıdakilerden olan gerçek :

  • [...]
  • Bir aşağıdaki durumların geçerli :
    • [...]
    • Sbir arabirim türüdür, Tbir sınıf türüdür ve Tbir finalsınıfı adlandırmaz.

Derleyici Yani bile olabilir davanız aslında kanıtlanabilir imkansız olduğunu anlamaya JLS Geçerli Java programı olarak tanımlar çünkü bayrak bir hata izin verilmez.

Yalnızca bir uyarı gösterilmesine izin verilir.


16
Ve dikkat çekmeye değer, String ile durumu yakalamanın nedeni, String'in son olmasıdır, böylece derleyici hiçbir sınıfın onu genişletemeyeceğini bilir.
MTilsted

5
Aslında, myDate = (Date) myStringbaşarısız kılan String "nihai" olduğunu sanmıyorum . JLS terminolojiyi kullanarak, deyim girişimleri dönüştürmek için S( Stringkadar) T( Date). Burada, Sbir arayüz tipi değildir, bu nedenle yukarıda belirtilen JLS koşulu uygulanmaz. Örnek olarak, bir Takvimi bir Tarihe yayınlamayı deneyin; hiçbir sınıf son olmasa da bir derleyici hatası alırsınız.
Mike Woinoski

1
Derleyicinin strList'in sadece ArrayList türünde olabileceğini kanıtlamak için yeterli statik analiz yapamayacağını hayal kırıklığına uğratmak veya bilmemek bilmiyorum.
Joshua

3
Derleyicinin kontrol etmesi yasaktır. Ancak buna hata demek yasaktır. Bu derleyiciyi uyumlu yapmaz. (Cevabımı gör ...)
Stephen C

3
Biraz lingo eklemek için derleyici tipi olduğunu kanıtlamak gerekir Date & Listise yaşanmaz , bunun olduğunu kanıtlamak için yeterli değildir ıssız (gelecekte olabilir) şu anda.
Polygnome

15

Örneğinizin genellemesini düşünelim:

List<String> strList = someMethod();       
Date d = (Date) strList;

Bunlar Date d = (Date) strList;derleme hatası olmamasının temel nedenleridir .

  • Sezgisel nedeni derleyici bu yöntem çağrısı tarafından döndürülen nesnenin kesin tipini bilmiyor (genel olarak) olmasıdır. Uygulayan bir sınıf olmanın yanı sıra List, aynı zamanda bir alt sınıf olması da mümkündür Date.

  • Teknik nedeni Java Dil Özellikleri "verir" olmasıdır daralması referans dönüşüm bu tip döküm karşılık gelir. JLS 5.1.6.1'e göre :

    "Bir daralma referans dönüşüm referans türünden mevcut Sbaşvuru tipi için Taşağıdakilerden tümü doğruysa:"

    ...

    5) " Sbir arabirim türüdür, Tbir sınıf türüdür ve Tbir finalsınıfı adlandırmaz."

    ...

    Farklı bir yerde, JLS ayrıca çalışma zamanında bir istisna atılabileceğini söylüyor ...

    JLS 5.1.6.1 saptamasının, yalnızca gerçek çalışma zamanı türlerinden ziyade ilgili değişkenlerin bildirilen türlerine dayandığını unutmayın . Genel durumda, derleyici gerçek çalışma zamanı türlerini bilmez ve bilemez.


Peki, Java derleyicisi neden oyuncuların işe yaramayacağına karar veremiyor?

  • Örneğimde, someMethodçağrı çeşitli türdeki nesneleri döndürebilir. Derleyici, yöntem gövdesini çözümleyebildi ve döndürülebilecek kesin tür kümesini belirleyebilse bile, çağıran kodu derledikten sonra birisinin farklı türler döndürmesini değiştirmesini durduracak hiçbir şey yoktur. JLS 5.1.6.1'in söylediklerini söylemesinin temel nedeni budur.

  • Senin örnekte, akıllı derleyici olabilir dökme başarılı olamaz anlamaya. Ve sorunu belirtmek için derleme zamanı uyarısı yayınlamasına izin verilir .

Öyleyse neden akıllı bir derleyicinin bunun bir hata olduğunu söylemesine izin verilmiyor?

  • Çünkü JLS bunun geçerli bir program olduğunu söylüyor. Dönemi. Buna hata adı veren herhangi bir derleyici Java uyumlu olmaz.

  • Ayrıca, JLS ve diğer derleyicilerin geçerli olduğunu söylediği Java programlarını reddeden herhangi bir derleyici , Java kaynak kodunun taşınabilirliği için bir engeldir.


4
Çağıran sınıfı derledikten sonra, çağrılan fonksiyon uygulamasının değişebileceği gerçeği için, derleme zamanında kanıtlanabilir olsa bile, callee'nin mevcut uygulamasıyla, almanın imkansız olduğu, bu daha sonraki çalışma zamanlarında böyle olmayabilir callee değiştiğinde veya değiştirildiğinde.
Peter - Monica

2
Bir derleyici çok akıllı olmaya çalıştığında ortaya çıkacak taşınabilirlik sorununu vurgulamak için oy verin.
Mike Woinoski

2

5.5.1. Referans Tipi Döküm:

Bir derleme referans tipi göz önüne alındığında, S(kaynak) ve bir derleme referans tipi T(hedef), bir döküm dönüşüm ile ilgili mevcut Siçin Tbir derleme zamanı hataları aşağıdaki kurallara bağlı alırlar.

[...]

Bir Sarayüz tipiyse:

  • [...]

  • Eğer Tson olmayan bir sınıf veya arabirimi, daha sonra bir üst tip mevcutsa Xarasında Tve süper tip Yarasında S, her iki şekilde, Xve Ykanıtlanmıştır farklı parametreli türleri, ve silmeler olduğu Xve Yaynı, bir derleme hatası oluşur.

    Aksi takdirde, döküm derleme zamanında her zaman yasaldır (çünkü Tuygulanmasa bile S, bir Tkudret alt sınıfı ).

List<String>olduğu Sve Dateolduğu Tsenin durumunda.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.