Soru Java 8 Çift küme parantez başlatma ve isim çarpışması


Aşağıdaki sınıfın adı verilen bir iç sınıfı vardır. Entry. Bu kod, derleyicinin varsaydığı gibi Java 8'de derlenmeyecektir. Entry çift ​​küme ayracı başlatıcısı içinde başvurulan türdür Map.Entry ve yok Scope.Entry. Bu kod, JDK'nın önceki sürümlerinde (en az 6 ve 7) derler ancak JDK 8'de bozulur. Benim sorum "neden?" Map.Entry Bu sınıfta içe aktarılmaz, bu nedenle derleyicinin değerin tür olduğunu varsaymak için bir neden yoktur Map.Entry. Anonim sınıflar için getirilen bazı gizli kapsamlar var mı?

Hata:

scope/Scope.java:23: error: incompatible types: scope.Scope.Entry cannot be converted to java.util.Map.Entry for (final Entry entry : entries) {
scope/Scope.java:22: error: cannot find symbol put(entry.getName(), entry);

Örnek kod:

package scope;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;

public class Scope {

    public static class Entry<T> {
        public String getName() {
            return "Scope";
        }
    }

    public static void main(String[] args) {
        final Set<Entry> entries = new HashSet<>();

        new HashMap<String, Entry>() {{
            // Why does the Java 8 compiler assume this is a Map.Entry
            // as it is not imported? 
            for (final Entry entry : entries) {
                put(entry.getName(), entry);
            }
        }};
    }
}

18
2017-11-13 16:12


Menşei


@tobias_k Bu gerçekten çift kaşlı ayraçlar değil. Anonim bir iç sınıf oluşturmak için bir çift parantez ve bir örnek başlatıcı bloğu için başka bir çift var. Bazı insanlar bunu çift kaşlı ayraçlar olarak biçimlendirmeyi severler, ancak gerçekten özel bir anlamı yoktur. - biziclop
@tobias_k Evet, uygulamada başlatıcı blokları her kurucunun başlangıcına kopyalanır. (Birden fazla blok varsa, kaynak kodunda göründükleri sırayla uygulanırlar.) - biziclop
Bu arada, "kaşlı ayraçlar" terimi benim bir evcil hayvanımdır. Onlar sadece "diş telleri". - Floegipoky
kullanım entries.stream().collect(toMap(Entry::getName, e->e)) (ile Collectors.toMap Statik olarak ithal edilen "çifte küme başlatma" yerine, berbat. - David Conrad
Sorun şudur: kapalı sınıfa bir referans katar ve haritayı kullandığı sürece çöp toplanmasını engeller. Tabii ki, bu bir noktada kötü olmayabilir, ama böyle bir haritayı ortaya çıkarmadan önce her seferinde durup düşünecek misin? Projenizdeki her geliştirici, bir kodu başka bir sınıfa taşımadan önce düşünecek mi? Bir kitleye bazı büyük devletler eklemeden önce, bir çift sınıftaki çifte deyimi kontrol edecekler mi? Bu deyimden kaçınırdım. Çok daha iyi yollar var. - David Conrad


Cevaplar:


Bu kesinlikle bir hata değil, çift kuşaklı başlatmanın kullanılmasının bir yan etkisi.

new HashMap<String, Entry>() {{
    for (final Entry entry : entries) {
        put(entry.getName(), entry);
    }
}};

Bu tür başlatma, temel olarak kötüye kullanımı akıllıca bir yoldur örnek başlatma blokları. Bir başlatma bloğu ile HashMap'ın anonim bir alt sınıfını oluşturur ve daha sonra bu bloğu çağırmadan önce varsayılan yapıcının başına kopyalar. Bu alt sınıf, Entry'ye ana içeriğinin kapsamına öncelik verir, iç içe geçmiş kapsamı değil. gölgeleme.

itibaren 8.1.6. Sınıf Beden ve Üye Bildirimleri

Eğer C kendisi yuvalanmış bir sınıfsa, aynı tanımlamalar olabilir.   Kapsayan kapsamlarda tür (değişken, yöntem veya tür) ve m olarak adlandırılır.   (Kapsamlar bloklar, sınıflar veya paketler olabilir.) Tüm bu gibi durumlarda,   üye m ilan etti veya C tarafından devralındı gölgeler (§6.4.1) diğer   Aynı tür ve isimlerin tanımları. [vurgu benim

İşte, C beyan edilen anonim iç sınıftır. O devraldığı için HashMap, java.util.Map.Entry gölgeler scope.Scope.Entry.

Önceki sürümlerde istediğin gibi derlenmiş olmasına rağmen, hiçbir fikrim yok. Bu davranış bu sürümlerde mevcuttu. 7), o yüzden çalışmamalıydı. Yani belki bu sürümler yüklenir.


25
2017-11-13 18:53



JLS'de bir sınıfın genişletilmesi nerede belirtilir? beyan süper sınıfın iç sınıfları? Sınıfı genişletmek sınıfın 'iç sınıflarına kesin olarak erişmenizi sağlar, ancak iç sınıfların beyanı başka bir yerde yapılır. Veya alt sınıfları ve beyanları neden eşit olarak yorumluyorsunuz? - jarnbjo
Evet, şimdi haklısın :) §6.4.1'de benzer bir şey bulmaya çalıştım. aslında belirtilir ve bu paragrafta bu durumun açıklaması yoktur. - jarnbjo


Tip üyelerin kapsamları ve gölgeleme bir derleyici için zor bir yerdir. Bununla ilgili hataların sayısı / sayısı - çoğunlukla iç içe / iç / anonim tipler. Olanı bulamıyorum kesinlikle Bu konuda ama bununla ilgili olabilecek bazı şeyler biliyorum. İşte Bu çok benzer bir durumda olan bir durumdur (kapalı tür yerine tip değişkeni).

Hangi şartnamenin gölgeleme ile ilgili olduğu konusunda da bir konu. JLS'ye referanslar içerir ve neyin ideal olmadığını tanımlar.


0
2017-11-13 22:45