valor - ¿Eclipse advierte sobre el acceso sintético para clases anidadas estáticas privadas en Java?
modificadores de acceso java pdf (6)
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 eso sea un capricho / error de Eclipse
Eso no es un capricho / error de Eclipse, solo una característica de Java. La especificación del lenguaje Java, 8.8.9 dice:
... si la clase se declara protegida, entonces el constructor predeterminado recibe implícitamente el modificador de acceso protegido ...
Mi compañero de trabajo sugirió que algunas de las configuraciones de advertencia y formato de código de Eclipse fueran más rigurosas. La mayoría de estos cambios tienen sentido, pero recibo esta extraña advertencia en Java. Aquí hay un código de prueba para reproducir el "problema":
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 mi nueva configuración de advertencia:
El acceso al constructor adjunto WeirdInnerClassJavaWarning.InnerClass () se emula mediante un método de acceso sintético. Aumentar su visibilidad mejorará su rendimiento.
¿Qué significa esto? La advertencia desaparece cuando cambio "clase estática privada" a "clase estática protegida", lo que no tiene sentido para mí.
Edición: finalmente me di cuenta de la solución "correcta". El problema real aquí parece ser que a esta clase estática privada anidada le falta un constructor público. Ese único retoque 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 que la clase sea una clase anidada privada (por lo que ninguna otra clase puede tener acceso a ella, incluidas las subclases de la clase adjunta) y quiero que sea una clase estática.
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 eso sea un capricho / error de Eclipse.
(disculpas, debería haberlo llamado NestedClass en lugar de InnerClass para que sea más claro).
Debería poder deshacerse de él utilizando el alcance predeterminado en lugar de privado o protegido, es decir,
static class InnerClass ...
También vale la pena señalar que al colocar su cursor en la línea de código con la advertencia y presionar ctrl-1, Eclipse puede ser capaz de solucionarlo automáticamente.
No puede crear una instancia de InnerClass desde WeirdInnerClassJavaWarning. Es privado, JVM no te lo permitiría, pero el lenguaje Java (por alguna razón) lo haría.
Por lo tanto, javac crearía un método adicional en InnerClass que solo devolvería una nueva InnerClass (), lo que le permitiría crear instancias de InnerClass desde WeirdInnerClassJavaWarning.
No creo que realmente necesites deshacerte de él porque la caída del rendimiento sería inmensamente pequeña. Sin embargo, usted puede si realmente quiere.
Para ayudar a la gente, esto es lo que obtiene si usa el código de clase original en la pregunta con
javac -XD-printflat WeirdInnerClassJavaWarning.java -d tmp
Salida en bruto, el compilador añadió los comentarios. Tenga en cuenta la adición de la clase privada y el constructor paquete sintético.
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 {
}
Por cierto, la configuración para desactivar la advertencia se encuentra en la página de Errores / Advertencias de Java en "Estilo de código" y se llama:
Acceso a un miembro no accesible de un tipo adjunto
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 queja porque una clase privada sin constructor explícito no puede ser instanciada desde afuera, excepto a través del método sintético que crea el compilador de Java. Si toma su código, lo compila y luego lo descompila con jad (*), obtiene lo siguiente (reformateado):
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 agrega un constructor protegido, el código sintético no es necesario. El código sintético es teóricamente, supongo, más lento por una cantidad mínima que el código no sintético que utiliza un constructor público o protegido.
(*) Para jad, me vinculé a una página de Wikipedia ... el dominio que albergaba este programa ha caducado, pero Wikipedia se vincula a otra que no he probado. Sé que hay otros descompiladores (posiblemente más recientes), pero este es el que empecé a usar. Nota: se queja cuando se descompilan los archivos de clase de Java recientes, pero aún así hace un buen trabajo.