2009-05-28 13 views
45

Mi compañero de trabajo sugirió que se hicieran más rigurosos los ajustes de formato de código y advertencia de Eclipse. La mayoría de estos cambios tienen sentido, pero recibo esta rara advertencia en Java. Aquí hay algunos códigos de prueba para reproducir el "problema":¿Advertencia de Eclipse sobre el acceso sintético para clases anidadas estáticas privadas en Java?

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  

La línea con el !!! me da esta advertencia en Eclipse con mis nuevas opciones de advertencia:

acceso a encerrar constructor WeirdInnerClassJavaWarning.InnerClass() se emula mediante un método de síntesis de acceso . Al aumentar su visibilidad, mejorará su rendimiento.

¿Qué significa esto? La advertencia desaparece cuando cambio "clase estática privada" a "clase estática protegida", lo cual no tiene sentido para mí.


edición: que finalmente descubrió la solución "correcta". El verdadero problema aquí parece ser que a esta clase estática privada anidada le falta un constructor público. Que un pellizco retira la advertencia:

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(); 
    } 
} 

Quiero la clase que sea una clase anidada privada (por lo que ninguna otra clase puede tener acceso a ella, incluyendo las subclases de la clase envolvente) y yo quiero que sea un estático clase.

Todavía no entiendo por qué hacer que la clase anidada sea protegida en lugar de privada es otro método para solucionar el "problema", pero tal vez sea una peculiaridad o error de Eclipse.

(disculpas, debería haber llamado NestedClass en lugar de InnerClass a ser más clara.)

Respuesta

41

Usted puede deshacerse de la advertencia de la siguiente manera:

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(); 
    } 
} 

Como han dicho otros, Eclipse se quejaba de que una clase privada con ningún constructor explícito no se pueden crear instancias desde el exterior, excepto a través del método de síntesis que el El compilador de Java crea.Si se toma el código, compilarlo, y luego descompilarlo con jad (*), se obtienen los siguientes (reordenada):

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); 
} 

Si añade un constructor protegido, el código sintético es innecesaria. El código sintético es teóricamente, supongo, más lento en una cantidad minúscula que el código no sintético que usa un constructor público o protegido.

(*) Para jad, he vinculado a una página de Wikipedia ... el dominio que alojó este programa ha expirado, pero la Wikipedia enlaza con otro que no he probado yo mismo. Sé que hay otros descompiladores (posiblemente más recientes), pero este es el que comencé a usar. Nota: Es se queja al descompilar archivos recientes de la clase Java, pero aún así hace un buen trabajo.

+0

Supongo que estaba en el proceso de publicación antes de realizar mi edición. En cualquier caso, esta parece ser la respuesta correcta. –

+0

Sí, tú y yo estábamos escribiendo al mismo tiempo. He extendido mi respuesta para explicar también por qué recibes la advertencia de Eclipse. – Eddie

+0

+1 sobre el descompilador, nunca supe que existiera tal cosa.Parece que debería enviar un error para Eclipse para que cambien el texto de esta advertencia, para que quede un poco más claro qué significa esto y cuál debería ser la solución. –

8

No se puede crear una instancia de InnerClass WeirdInnerClassJavaWarning. Es privado, JVM no te lo permitió, pero el lenguaje Java (por alguna razón) sí lo haría.

Por lo tanto, javac crearía un método adicional en InnerClass que simplemente devolvería una nueva InnerClass(), lo que le permitiría crear instancias de InnerClass desde WeirdInnerClassJavaWarning.

No creo que realmente deba deshacerse de él porque la caída del rendimiento sería muy pequeña. Sin embargo, puedes si realmente quieres.

+2

+1 la mejora de rendimiento debería ser completamente insignificante en una JVM moderna. Eclipse está exagerando, me gustaría apagar esa advertencia por completo. – skaffman

+0

"No se puede crear una instancia de InnerClass de WeirdInnerClassJavaWarning. Es privado, JVM no se lo permitió, pero el lenguaje Java (por alguna razón) sí lo haría". No hay un constructor presente y el lenguaje Java creará automágicamente un constructor público sin argumentos, ninguno está presente. Que esta magia está sucediendo es lo que Eclipse estaba advirtiendo. – Powerlord

+1

Supongo que este constructor sería privado en el caso de una clase interna privada. De lo contrario, esta advertencia no tiene ningún sentido. – alamar

0

Usted debe ser capaz de deshacerse de él utilizando el ámbito predeterminado en lugar de privada o protegida, es decir

static class InnerClass ... 

Es también digno de mención que mi colocando el cursor en la línea de código con la advertencia y Al presionar ctrl-1, Eclipse puede solucionarlo automáticamente.

+0

gracias, pero no quiero eso, debería ser no visible para las clases que no sean la clase adjunta. –

+1

Es posible que desee suprimir la advertencia en este caso, ya que la advertencia de rendimiento de Eclipse es irrelevante para sus necesidades. – izb

+0

La configuración relevante es "Acceso a un miembro no accesible de un tipo adjunto" – akauppi

3

Todavía no entiendo por qué hacer la clase anidada protegida en lugar de privada es otro método para fijar el "problema", pero tal vez eso es una peculiaridad/fallo de Eclipse

Eso no es una peculiaridad/error de Eclipse, solo una característica de Java. El Java Language Specification, 8.8.9 dice:

... si la clase se declara protegida, entonces el constructor por defecto se da implícitamente el modificador de acceso protegido ...

+0

... y protegido y privado tienen diferentes implicaciones para el adjuntar clases? Pensé que la única diferencia era cómo se otorga el acceso a * subclases *. –

+1

No tiene implicaciones en el nivel del código fuente (compilador), sino en el nivel del código de bytes (máquina virtual). Mientras sepa, la JVM no conoce las clases anidadas, por eso obtienes un archivo .class adicional para ellas. El compilador debe crear métodos sintéticos para que la clase "externa" pueda acceder a los miembros privados de la clase anidada (en tiempo de ejecución). (BTW: protected también incluye el acceso al paquete, que sería suficiente para evitar la advertencia) (BTW2: según lo definido por el JLS, las clases anidadas estáticas no son clases internas ...) –

19

Por cierto, el ajuste para activar la alerta apagado está en la página de Java Errores/Advertencias bajo "estilo código" y se llama:

acceso a un miembro no accesible de un tipo envolvente

+1

Eso ya estaba configurado para Ignorar para mí, sin embargo, Todavía veo las advertencias. Quizás algo ha cambiado en Juno. –

+0

¿Es posible que esté configurado en Advertencia en la configuración específica del proyecto? – robinst

+0

Sé lo patético que parece ser, pero si la advertencia persiste, agregue un personaje en algún lugar y guarde el archivo. La advertencia desaparecerá después. – Blauhirn

2

Para ayudar a la gente a cabo, esto es lo que se obtiene si se utiliza el código de la clase original en la pregunta con

javac -XD-printflat WeirdInnerClassJavaWarning.java -d tmp 

salida de crudo, compilador añade los comentarios. Tenga en cuenta la adición de la clase privada del paquete sintético y el constructor.

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 { 
} 
Cuestiones relacionadas