java - tipos - Método de acceso de la clase anónima externa desde la clase anónima interna
meter una clase dentro de otra java (3)
Desde Java 8 la solución es bastante fácil. Solo guarda la referencia del método en una variable.
ReturnsANumber v = new ReturnsANumber() {
int theNumber() {
return 119;
}
public int getIt() {
Supplier<Integer> supplier = this::theNumber;
ReturnsANumber w = new ReturnsANumber() {
int theNumber() {
return 1;
}
public int getIt() {
return supplier.get();
}
};
return w.getIt();
}
};
Almacenar el objeto exterior también podría hacer el truco. Pero solo para métodos heredados :
interface ReturnsANumber {
int theNumber();
int getIt();
}
public int getIt() {
ReturnsANumber outer = this;
ReturnsANumber w = new ReturnsANumber() {
public int theNumber() {
return 1;
}
public int getIt() {
return outer.theNumber();
}
};
return w.getIt();
}
También puede almacenar la referencia del método o el objeto externo como un campo.
Actualizar
@Holger propuso otra solución. Puedes pasar tu objeto exterior a un lambda:
ReturnsANumber v = new ReturnsANumber() {
...
@Override
public int getIt() {
ReturnsANumber w = Optional.of(this).map(outer ->
new ReturnsANumber() {
int theNumber() {
return 1;
}
public int getIt() {
return outer.theNumber();
}
}).get();
return w.getIt();
}
};
Hago una instancia de una clase anónima con un método que crea una instancia de otra clase anónima, y desde esta clase anónima interna quiero llamar a un método que pertenece a la clase anónima externa. Para ilustrarlo, supongamos que tengo esta interfaz:
interface ReturnsANumber {
int getIt();
}
Y luego, en algún lugar de mi código, hago esto:
ReturnsANumber v = new ReturnsANumber() {
int theNumber() {
return 119;
}
public int getIt() {
// In a modern version of Java, maybe I could do
// var a = this;
// and then call a.theNumber();
ReturnsANumber w = new ReturnsANumber() {
int theNumber() {
return 1;
}
public int getIt() {
return this.theNumber();
}
};
return w.getIt();
}
};
System.out.println("The number is " + v.getIt());
Pregunta: En el método más interno getIt
, quiero llamar a theNumber()
pertenece a la clase anónima más externa. ¿Cómo puedo lograr eso sin usar la función Java 10 var (como se indica en el código)?
Aclaración: Idealmente, la clase anónima externa no debería necesitar saber que la clase interna desea llamar a su método theNumber
. La idea es crear un código que permita que la clase interna llame sin ambigüedad a cualquier método en la clase externa.
En otras palabras, ¿cómo puedo hacer que este código aparezca: The number is 119
(en lugar de mostrar The number is 1
)
Motivación : alguien podría preguntarme por qué quiero hacer esto de todos modos: estoy escribiendo algún tipo de generador de código y quiero estar seguro de que el código que estoy generando no es ambiguo.
No hay ninguna palabra clave para acceder a la clase anónima adjunta.
Pero una solución podría ser enviar un proxy al método en la clase anónima externa y hacer una referencia no calificada:
ReturnsANumber v = new ReturnsANumber() {
int theNumber() {
return 119;
}
//Just a different name for theNumber()
int theNumberProxy() {
return theNumber();
}
public int getIt() {
ReturnsANumber w = new ReturnsANumber() {
int theNumber() {
return 1;
}
public int getIt() {
return theNumberProxy(); //calls enclosing class''s method
}
};
return w.getIt();
}
};
La necesidad de tal maniobra debe ser prueba suficiente de que la estructura de su clase no es ideal y podría ser una trampa de mantenimiento. Simplemente podría reemplazar la primera clase anónima con una clase estática anidada, por ejemplo.
Si puedes extender la interfaz:
public class Test {
interface ReturnsANumber {
int theNumber();
int getIt();
}
public static void main(String[] args) {
ReturnsANumber v = new ReturnsANumber() {
public int theNumber() {
return 119;
}
public int getIt() {
final ReturnsANumber that = this;
// In a modern version of Java, maybe I could do
// var a = this;
// and then call a.theNumber();
ReturnsANumber w = new ReturnsANumber() {
public int theNumber() {
return 1;
}
public int getIt() {
return that.theNumber();
}
};
return w.getIt();
}
};
System.out.println("The number is " + v.getIt());
}
}