2009-05-28 12 views
45

Mój współpracownik zasugerował, aby kilka z ustawień formatowania i ostrzeżeń Eclipse było bardziej rygorystycznych. Większość tych zmian ma sens, ale dostaję to jedno dziwne ostrzeżenie w Javie. Oto kod testowy do odtworzenia "problemu":Ostrzeżenie Eclipse na temat syntetycznego akcesorium dla prywatnych statycznych klas zagnieżdżonych w Javie?

package com.example.bugs; 

public class WeirdInnerClassJavaWarning { 
    private static class InnerClass 
    { 
     public void doSomething() {} 
    } 

    final private InnerClass anInstance; 

    { 
     this.anInstance = new InnerClass(); // !!! 
     this.anInstance.doSomething(); 
    } 
} 
// using "this.anInstance" instead of "anInstance" prevents another warning, 
// Unqualified access to the field WeirdInnerClassJavaWarning.anInstance  

Linia z !!! Daje mi to ostrzeżenie w Eclipse z moimi nowymi ustawieniami Ostrzeżenie:

Dostęp do załączając konstruktora WeirdInnerClassJavaWarning.InnerClass() jest emulowane przez syntetyczną accessor metody. Zwiększenie jego widoczności zwiększy Twoją wydajność.

Co to oznacza? Ostrzeżenie zniknie, gdy zmienię "prywatną klasę statyczną" na "chronioną klasę statyczną", co nie ma dla mnie żadnego sensu.


edit: w końcu zorientowali się, "prawidłowy" poprawkę. Prawdziwym problemem wydaje się być to, że tej zagnieżdżonej prywatnej klasie statycznej brakuje publicznego konstruktora. Że jeden uszczypnąć usuwane ostrzeżenie:

package com.example.bugs; 

public class WeirdInnerClassJavaWarning { 
    private static class InnerClass 
    { 
     public void doSomething() {} 
     public InnerClass() {} 
    } 

    final private InnerClass anInstance; 

    { 
     this.anInstance = new InnerClass(); 
     this.anInstance.doSomething(); 
    } 
} 

chcę klasa być prywatny klasy zagnieżdżone (więc żadna inna klasa może mieć do niego dostęp, w tym podklas klasy okalającego) i chcę go mieć statyczny klasa.

Nadal nie rozumiem, dlaczego tworzenie zagnieżdżonej klasy chronionej, a nie prywatnej, jest inną metodą naprawy "problemu", ale być może jest to dziwactwo/błąd Eclipse.

(przepraszam, powinienem nazwali to NestedClass zamiast InnerClass być bardziej jasne.)

Odpowiedz

41

można pozbyć się ostrzeżenia, co następuje:

package com.example.bugs; 

public class WeirdInnerClassJavaWarning { 
    private static class InnerClass { 
     protected InnerClass() {} // This constructor makes the warning go away 
     public void doSomething() {} 
    } 

    final private InnerClass anInstance; 
    { 
     this.anInstance = new InnerClass(); 
     this.anInstance.doSomething(); 
    } 
} 

Jak mówili inni, Eclipse narzeka ponieważ prywatny klasa bez wyraźnej konstruktor nie może być instancja z zewnątrz, z wyjątkiem metodą syntetyczną, że Kompilator Java tworzy.Jeśli wziąć swój kod, skompilować go, a następnie dekompilować go jad (*), pojawi się następujący (sformatowany):

public class Test { 
    private static class InnerClass { 
    public void doSomething() {} 
    // DEFAULT CONSTRUCTOR GENERATED BY COMPILER: 
    private InnerClass() {} 

    // SYNTHETIC METHOD GENERATED BY THE JAVA COMPILER:  
    InnerClass(InnerClass innerclass) { 
     this(); 
    } 
    } 

    public Test() { 
    anInstance.doSomething(); 
    } 

    // Your instance initialization as modified by the compiler: 
    private final InnerClass anInstance = new InnerClass(null); 
} 

jeśli dodać zabezpieczony konstruktora, kod syntetyczny jest niepotrzebna. Syntetyczny kod teoretycznie jest, moim zdaniem, wolniejszy o wiele mniejszy od niesyntetycznego kodu przy użyciu publicznego lub chronionego konstruktora.

(*) Dla Jad, połączyłem się ze stroną w Wikipedii ... Domena, która hostowała ten program wygasła, ale Wikipedia łączy się z inną, której sam nie przetestowałem. Wiem, że są inne (prawdopodobnie nowsze) dekompilatory, ale to jest ten, którego zacząłem używać. Uwaga: To narzeka podczas dekompilacji ostatnich plików klasy Java, ale nadal robi dobrą robotę.

+0

Tak, ty i ja piszemy w tym samym czasie. Rozszerzyłem moją odpowiedź, aby również wyjaśnić, dlaczego otrzymujesz ostrzeżenie Eclipse. – Eddie

+0

+1 o dekompilatorze, nigdy nie wiedziałem, że coś takiego istnieje.Wygląda na to, że powinienem zgłosić błąd dla Eclipse, że powinni zmienić tekst tego ostrzeżenia, aby było trochę bardziej zrozumiałe, co to oznacza i jaka powinna być poprawka. –

+5

Najlepszym rozwiązaniem, o ile nie jest to projekt J2ME, jest wyłączenie ostrzeżenia w Eclipse i napisanie kodu zgodnie z intencją użytkownika. Po JIT wynik będzie albo znikomy, albo zero. – Darron

8

Nie można utworzyć wystąpienia InnerClass z WeirdInnerClassJavaWarning. Jest prywatny, JVM nie pozwalał ci, ale język Java (z jakiegoś powodu) by.

Dlatego też javac wykona dodatkową metodę w InnerClass, która właśnie zwróci nową InnerClass(), umożliwiając tworzenie instancji InnerClass z WeirdInnerClassJavaWarning.

Nie sądzę, że naprawdę trzeba się go pozbyć, ponieważ spadek wydajności byłby niewspółmiernie mały. Możesz jednak, jeśli naprawdę chcesz.

+2

+1 Poprawa wydajności powinna być całkowicie nieistotna dla nowoczesnej maszyny JVM. Eclipse jest tutaj po prostu zbyt entuzjastyczny, zupełnie wyłączyłbym to ostrzeżenie. – skaffman

+0

"Nie można utworzyć instancji InnerClass z WeirdInnerClassJavaWarning. Jest ona prywatna, JVM nie pozwalałaby na to, ale język Java (z jakiegoś powodu) byłby". Nie ma żadnego konstruktora, a język Java automagicznie utworzy publiczny konstruktor no-arg, którego nie ma. Ta magia jest tym, o czym ostrzegał Eclipse. – Powerlord

+1

Myślę, że ten konstruktor byłby prywatny w przypadku prywatnej klasy wewnętrznej. W przeciwnym razie to ostrzeżenie nie ma sensu. – alamar

0

powinien być w stanie pozbyć się go za pomocą domyślnego zakresu zamiast prywatne lub chronione, tj

static class InnerClass ... 

Warto również zauważyć, że mój umieszczając kursor na linii kodu z ostrzeżeniem i naciśnięcie ctrl-1, Eclipse może być w stanie naprawić to automatycznie dla ciebie.

+0

dziękuję, ale nie chcę tego, powinno być niewidoczne dla klas innych niż otaczająca klasa. –

+1

W takim przypadku może być konieczne wyłączenie ostrzeżenia, ponieważ ostrzeżenie o wydajności firmy Eclipse nie ma znaczenia dla twoich potrzeb. – izb

+0

Zakładam, że byłeś w trakcie publikowania, zanim dokonałem edycji. W każdym razie wydaje się, że jest to właściwa odpowiedź. – akauppi

3

ja nadal nie rozumiem, dlaczego co zagnieżdżony klasy chronione niż prywatny jest inna metoda ustalania „problem”, ale być może jest to dziwactwo/bug Eclipse

To nie jest dziwactwo/błąd Eclipse, tylko cecha Javy. Java Language Specification, 8.8.9 mówi:

... jeśli klasa jest zadeklarowana chronione, wówczas konstruktor domyślny jest niejawnie otrzymują modyfikator dostępu zabezpieczonego ...

+0

... i chronione i prywatne mają różne implikacje dla zamykania klas? Myślałem, że jedyną różnicą jest to, w jaki sposób dostęp jest przyznawany * podklasom *. –

+1

Nie ma to wpływu na poziom kodu źródłowego (kompilator), ale na poziomie kodu bajtowego (maszyna wirtualna). O ile wiem, JVM nie zna klas zagnieżdżonych, dlatego dostajesz dla nich dodatkowy plik .class. Kompilator musi tworzyć metody syntetyczne, aby klasa "zewnętrzna" mogła uzyskać dostęp do prywatnych elementów klasy zagnieżdżonej (w czasie wykonywania). (BTW: protected obejmuje również dostęp do pakietu, który byłby wystarczający, aby uniknąć ostrzeżenia) (BTW2: zgodnie z definicją JLS, statyczne zagnieżdżone klasy nie są klasami wewnętrznymi ...) –

19

Nawiasem mówiąc, ustawienie, aby włączyć ostrzeganie off jest na stronie Błędy/ostrzeżenia Java pod „styl Code” i nazywa się:

dostęp do niedostępnej członek typu otaczającej

+1

To było już ustawione dla Ignore dla mnie, ale ja nadal widzę ostrzeżenia. Być może coś się zmieniło w Juno. –

+0

Czy to możliwe, że jest ustawione na Ostrzeżenie w ustawieniach specyficznych dla projektu? – robinst

+0

Wiem, jak żałosny to wydaje się być, ale - jeśli ostrzeżenie trwa, dodaj gdzieś znak i zapisz plik. Ostrzeżenie zniknie później. – Blauhirn

2

Aby pomóc ludzie się tutaj jest to, co masz, jeśli używasz oryginalnego kodu klasy w pytaniu z

javac -XD-printflat WeirdInnerClassJavaWarning.java -d tmp 

wyjście Raw, kompilator dodaje komentarze. Zwróć uwagę na dodanie klasy prywatnej i konstruktora pakietu syntetycznego.

public class WeirdInnerClassJavaWarning { 
    { 
    } 

    public WeirdInnerClassJavaWarning() { 
     super(); 
    } 
    { 
    } 
    private final WeirdInnerClassJavaWarning$InnerClass anInstance; 
    { 
     this.anInstance = new WeirdInnerClassJavaWarning$InnerClass(null); 
     this.anInstance.doSomething(); 
    } 
} 

class WeirdInnerClassJavaWarning$InnerClass { 

    /*synthetic*/ WeirdInnerClassJavaWarning$InnerClass(WeirdInnerClassJavaWarning$1 x0) { 
     this(); 
    } 

    private WeirdInnerClassJavaWarning$InnerClass() { 
     super(); 
    } 

    public void doSomething() { 
    } 
} 

/*synthetic*/ class WeirdInnerClassJavaWarning$1 { 
} 
Powiązane problemy