16

Hier ist ein einfaches Beispiel für einige Code, Java 6 mit kompiliert, aber nicht kompiliert in Java 7.Änderungen der Zugriff von Variablen für generische Klassen in Java 7

public class Test<T extends Test> { 

    private final int _myVar; 

    public Test(int myVar) { 
    _myVar = myVar; 
    } 

    public int get(TestContainer<T> container){ 
    T t = container.get(); 
    return t._myVar; 
    } 

    private static class TestContainer<T extends Test> { 
    private final T _test; 
    private TestContainer(T test) { 
     _test = test; 
    } 
    public T get(){ 
     return _test; 
    } 
    } 
} 

In Java 7, scheitert es an kompilieren im get(TestContainer<T> container) Verfahren, mit dem Fehler:

error: _myVar has private access in Test

ich verstehe nicht, warum das nicht mehr kompiliert - in meinem Kopf es sollte. Die Variable t ist vom Typ T, die Test muss erweitert werden. Es versucht, auf das Feld _myVar einer Instanz Test innerhalb der Klasse Test zuzugreifen.

der Tat, wenn ich die Methode get(TestContainer<T> container) der folgenden ändern, kompiliert es (ohne Warnungen):

public int get(TestContainer<T> container){ 
    Test t = container.get(); 
    return t._myVar; 
} 
  • Warum funktioniert das nicht mehr kompilieren?
  • War das ein Fehler in Java 6? Wenn ja warum?
  • Ist das ein Fehler in Java 7?

ich eine Google und suchten in der Oracle-Bug-Datenbank gehabt haben, haben aber nichts dazu gefunden ...

+5

Dies ist ein Fehler in Java 6 war: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7022052 – pingw33n

+0

@ pingw33n, sollten Sie schreiben, dass als Antwort. –

+0

@ pingw33n, und dann kann ich es akzeptieren ... obwohl, wenn jemand, der ein besseres Verständnis der JLS hat, den Abschnitt "Bewertung" des Fehlerberichts erklären kann, würde ich das auch begrüßen. – amaidment

Antwort

9

§4.9 ... Then the intersection type has the same members as a class type (§8) with an empty body, direct superclass Ck and direct superinterfaces T1', ..., Tn', declared in the same package in which the intersection type appears.

Von meinem Verständnis dieses JLS Teils, Ihr Fall mit einer Variable vom Typ <T extends Test> erstellt die folgende Kreuzung:

package <the same as of Test>; 

class I extends Test {} 

Deshalb, wenn Sie Mitglieder des Typs zugreifen T Sie tatsächlich Mitglieder der Kreuzung zugreifen Geben Sie I ein. Da private Member niemals von Subtypen geerbt werden, schlägt der Zugriff auf solche Member mit Kompilierfehler fehl. Auf dem anderen Seite Zugang zu dem Paket-privaten (Standard) und geschützte Mitglieder durch die Tatsache, darf die Kreuzung für diesen

... declared in the same package in which the intersection type appears.

0

Siehe Kommentar des @ pingw33n für die Antwort, aber die Art und Weise, dies zu beheben ist um die generischen Parameter der verschachtelten Klasse zu entfernen. Wenn Sie nicht einen Anwendungsfall haben, bei dem die inneren und äußeren T's unterschiedlich sein können, sind sie überflüssig. Alles, was sie tun, verursacht diesen Kummer.

+0

Sie schlagen vor, es einfach zu machen: 'private statische Klasse TestContainer'? Da die innere Klasse statisch ist, kann man nicht (in den kurzen Worten des Compilers) * einen statischen Verweis auf den nicht statischen Typ T * machen. –

+0

Ich habe einen Anwendungsfall - das Äquivalent von TestContainer ist eigentlich eine separate Klasse - aber das ist nur ein SSCCE, um das Compiler-Problem zu demonstrieren, mit dem ich konfrontiert war. – amaidment

0

Eine Abhilfe ist, ist die generische Instanz auf den Beton übergeordneten Typen zu werfen, die den privaten Bereich erklärt, z.B

public int get(TestContainer<T> container){ 
    T t = container.get(); 
    return ((Test) t)._myVar; 
}