Java 8, lambda ifadeleri gibi önemli yeni dil özelliklerini sunar.
Dildeki bu değişikliklere, derlenmiş bayt kodunda, bir retrotranslator kullanmadan Java 7 sanal makinesinde çalışmasını engelleyecek önemli değişiklikler eşlik ediyor mu?
Java 8, lambda ifadeleri gibi önemli yeni dil özelliklerini sunar.
Dildeki bu değişikliklere, derlenmiş bayt kodunda, bir retrotranslator kullanmadan Java 7 sanal makinesinde çalışmasını engelleyecek önemli değişiklikler eşlik ediyor mu?
Yanıtlar:
Hayır, kaynak kodunuzda 1.8 özellik kullanmak 1.8 VM'yi hedeflemenizi gerektirir. Yeni Java 8 sürümünü denedim ve derlemeyi denedim -target 1.7 -source 1.8
ve derleyici reddediyor:
$ javac Test -source 1.8 -target 1.7
javac: source release 1.8 requires target release 1.8
Varsayılan yöntemler, Java 7'de bayt kodu ve JVM'de bu tür değişikliklerin yapılmasını imkansız kılar. Varsayılan yöntemleri arayan tarafında statik yöntemlerle taklit etmeye çalışmak aynı sonuçları üretmez, çünkü varsayılan yöntemler alt sınıflarda geçersiz kılınabilir. Retrolambda , varsayılan yöntemler backporting için sınırlı desteğe sahiptir, ancak yeni JVM özellikleri gerektirdiğinden asla tam olarak rapor edilemez.
Gerekli API sınıfları orada mevcut olsaydı, Lambdas Java 7'de olduğu gibi çalışabilirdi. İnfürodinamik talimat Java 7'de bulunur, ancak lambda sınıflarını derleme zamanında (böylece JDK 8'in erken yapısını bu şekilde yapar) oluşturacak şekilde uygulamak mümkün olurdu, bu durumda herhangi bir Java sürümü üzerinde çalışacaktır. (Oracle gelecekteki prova için lambdas için invokedynamic kullanmaya karar verdi; belki bir gün JVM birinci sınıf işlevlere sahip olacaktır, bu nedenle invokedynamic, her lambda için bir sınıf oluşturmak yerine bunları kullanmak için değiştirilebilir, böylece performansı iyileştirir.) Retrolambda'nın yaptığı tüm bu invokinamik talimatları işlediğini ve anonim sınıflarla değiştirdiğini; bir lamdba invokedynamic ilk kez çağrıldığında Java 8'in çalışma zamanında yaptığı ile aynı.
Ek Açıklamaları tekrarlamak sadece sözdizimsel şekerdir. Önceki sürümlerle bayt kod uyumludurlar. Java 7'de, kendinize tekrarlanan ek açıklamaları içeren bir konteyner ek açıklamasının uygulama ayrıntılarını gizleyen yardımcı yöntemleri (örn. GetAnnotationsByType ) uygulamanız gerekir.
AFAIK, Tür Ek Açıklamaları yalnızca derleme zamanında mevcuttur, bu nedenle bayt kodu değişiklikleri gerektirmemelidir, bu nedenle yalnızca Java 8 ile derlenmiş sınıfların bayt kodu sürüm numarasını değiştirmek, Java 7'de çalışabilmeleri için yeterli olmalıdır.
Yöntem parametre adları Java 7 ile bayt kodunda bulunur, bu da uyumludur. Yöntemin bayt kodunu okuyarak ve yöntemin hata ayıklama bilgilerindeki yerel değişken adlarına bakarak bunlara erişebilirsiniz. Örneğin Spring Framework, @PathVariable'ı uygulamak için tam olarak bunu yapar ; bu nedenle, çağırabileceğiniz bir kitaplık yöntemi vardır. Soyut arabirim yöntemlerinin bir yöntem gövdesi olmadığından, bu hata ayıklama bilgileri Java 7'deki arabirim yöntemleri ve AFAIK için de Java 8'de bulunmaz.
Diğer yeni özellikler çoğunlukla yeni API'ler, HotSpot'taki iyileştirmeler ve araçlardır. Yeni API'ler bazıları 3. parti kütüphaneleri (örn olarak mevcuttur ThreeTen-backport ve streamsupport ).
Summa summarum, varsayılan yöntemler yeni JVM özellikleri gerektirir, ancak diğer dil özellikleri gerektirmez. Bunları kullanmak istiyorsanız, kodu Java 8'de derlemeniz ve ardından Retrolambda ile bayt kodunu Java 5/6/7 biçimine dönüştürmeniz gerekir. En azından bayt kodu sürümünün değiştirilmesi gerekir ve javac izin vermez, -source 1.8 -target 1.7
bu nedenle bir retrotranslator gereklidir.
Bildiğim kadarıyla JDK 8'deki bu değişikliklerin hiçbiri yeni bayt kodlarının eklenmesini gerektirmedi. Lambda enstrümantasyonunun bir kısmı invokeDynamic
(zaten JDK 7'de mevcut olan) kullanılarak yapılmaktadır. Bu nedenle, JVM komut kümesi açısından hiçbir şey kod tabanını uyumsuz yapmamalıdır. Yine de, JDK 8 kodunu derlemek / önceki JDK'lar altında çalıştırmak zorlaştıracak API ile ilişkili ve derleyici geliştirmeleri bir sürü vardır (ancak bunu denemedim).
Belki de aşağıdaki referans materyalleri, lambda ile ilgili değişikliklerin nasıl gerçekleştirildiğinin anlaşılmasını bir şekilde zenginleştirmeye yardımcı olabilir.
Bunlar, olayların başlık altında nasıl kullanıldığını ayrıntılı olarak açıklar. Belki sorularınızın cevabını orada bulabilirsiniz.
class C extends A with B
normal arayüzler A
ve B
ve eşlik sınıfları ile uygulanır A$class
ve B$class
. class C
, yöntemleri statik tamamlayıcı sınıflara iletir. Benlik türleri hiç uygulanmaz, lambdalar derleme zamanında soyut iç sınıflara aktarılır, yani bir new D with A with B
ifade. Desen eşleştirme, if-else yapılarının bir demetidir. Yerel olmayan iadeler? lambda denemeyi yakalama mekanizması. Geriye kalan bir şey var mı? (İlginçtir, benim scalac'ım 1.6 varsayılan olduğunu söylüyor)
Bir "retrotranslator" kullanmak istiyorsanız Esko Luontola'nın mükemmel Retrolambda'sını deneyin: https://github.com/orfjackal/retrolambda
Yapabilirsin -source 1.7 -target 1.7
o zaman derler. Ancak lambdas gibi java 8'e özgü özellikleriniz varsa derlenmeyecek
-source 1.7
uçmuyor.