2016-03-07 4 views
17

Je suis sur la résolution des énigmes Java et sommes tombés sur celui-ci:1.7 vs JDK 1.6 JDK classes internes différence d'héritage

public class Outer { 
    class Inner1 extends Outer {} 
    class Inner2 extends Inner1 {} 
} 

Lors de la compilation avec ce code javac 1.6.0_45 je reçois, comme prévu, cette erreur:

Outer.java:8: cannot reference this before supertype constructor has been called 
class Inner2 extends Inner1 {}                         
^ 

Ceci est dû compilateur génère constructeur par défaut pour Inner2 classe avec un code similaire, ce qui explique l'erreur ci-dessus:

Inner2() { 
    this.super(); 
} 

Et il est maintenant évident, parce que vous ne pouvez vraiment pas faire en Java 1.6.0_45, JLS 8.8.7.1 (comme je peux deviner):

An explicit constructor invocation statement in a constructor body may not refer to any instance variables or instance methods declared in this class or any superclass, or use this or super in any expression; otherwise, a compile-time error occurs.

Voir (accepted answer en Odd situation for "cannot reference this before supertype constructor has been called")

Mais si j'essaie de le compiler avec javac 1.7.0_79 - c'est OK!

Et voici la question - Qu'est-ce qui a été changé dans Java 1.7, que ce code est maintenant correct?

Merci d'avance!

+3

@EJP avez-vous vérifié la [réponse acceptée] (http://stackoverflow.com/a/3383555/365237) de celle-ci, car celle-ci semble pertinente – eis

+2

@EJP, aussi, 'this.super() 'n'est ** pas ** équivalent à' super() '. Si vous essayez de le faire dans une classe non-imbriquée non interne, vous obtiendrez une erreur de compilation, avant [JLS1.6 8.8.7.1]. 'Si S n'est pas une classe interne, ou si la déclaration de S se produit dans un contexte statique, il n'existe pas d'instance immédiatement adjacente de S par rapport à S. Une erreur compiletime se produit si l'invocation du constructeur de la superclasse est un appel de constructeur qualifié de superclasse. Similaire à [JLS1.7 8.8.7.1]. – ar4ers

Répondre

6

On dirait qu'il ya eu une discussion du même problème que le bug JDK-6708938: Synthetic super-constructor call should never use 'this' as a qualifier sur le bug tracker Java .

Aussi, je pense que ce serait génial pour vous de jeter un oeil à d'autres questions connexes de la précédente, par exemple JDK-4903103: Can't compile subclasses of inner classes .

Notez les versions corrigées des deux bogues. Par conséquent, voir Maintenance Review of JSR 901 (Java Language Specification) for Java SE 7.

De The Java Language Specification Third Edition

Otherwise, S is an inner member class (§8.5). It is a compile-time error if S is not a member of a lexically enclosing class, or of a superclass or superinterface thereof. Let O be the innermost lexically enclosing class of which S is a member, and let n be an integer such that O is the n th lexically enclosing class of C . The immediately enclosing instance of i with respect to S is the n th lexically enclosing instance of this.

et de révision de la maintenance de la JSR 901 (Java Language Specification) pour Java SE 7 (version complète, à la page 242, le texte en bleu) ou même dans The Java Language Specification, Java SE 7 Edition (juste avant la section 8.8. 8)

Otherwise, S is an inner member class (§8.5).

Let O be the innermost lexically enclosing class of S, and let n be an integer such that O is the n'th lexically enclosing class of C.

The immediately enclosing instance of i with respect to S is the n'th lexically enclosing instance of this.

Ainsi vous pouvez voir que la partie avec l'erreur de compilation a disparu.

+0

Merci pour votre réponse! Maintenant, j'ai la moindre idée que quelque chose a définitivement été changé! Mais je ne comprends pas exactement quoi. Je n'ai pas trouvé de différences majeures entre 'JLS SE 7' et' JLS Third Edition' dans toute la section 8.8. – ar4ers

+1

@ ar4ers J'ai ajouté les différences de ces deux versions de JSL liées au problème. – NikolayKondratyev

+0

Grand merci pour vos notes supplémentaires! Maintenant, je comprends la différence. Et, peut-être savez-vous également, où peut-on trouver une définition de comportement spécifique (comme la création d'un constructeur synthétique)? Comme je peux le deviner - c'est JVMS, est-ce que je vais bien? – ar4ers

-1

Je soupçonne que c'est doit faire avec invoke dynamic qui a été ajouté en Java 1.7 pour préparer le lambda de Java 8.

+0

Je l'ai vérifié en premier lieu. Malheureusement, ce n'est pas le cas. J'ai utilisé 'javap -c' sur les trois fichiers' .class', 'Outer.class',' Outer $ Inner1.class' et 'Outer $ Inner2.class'.Aucune preuve de 'invokedynamic', seulement' invokespecial' et 'putfield'. Je suis actuellement à l'étude de ce problème, mais aucun résultat pour le moment. – ar4ers