example - Cómo determinar rápidamente si un método está anulado en Java
overriding java example (8)
Existe una posible optimización que podría aplicar a uno de mis métodos, si puedo determinar que otro método en la misma clase no está anulado. Es solo una ligera optimización, por lo que la reflexión está fuera de discusión. ¿Debería hacer un método protegido que devuelva si el método en cuestión está anulado o no, de modo que una subclase puede hacer que se devuelva verdadero?
Bueno, mi optimización es un pequeño rendimiento caso por caso, y solo acelera mucho las cosas porque se llama cientos de veces por segundo.
Es posible que desee ver lo que puede hacer el optimizador de Java. Su optimización codificada a mano podría no ser necesaria.
Si decide que la optimización codificada a mano es necesaria, el enfoque del método protegido que describió no es una buena idea porque expone los detalles de su implementación.
¿Cuántas veces espera que se llame a la función durante la vida útil del programa? La reflexión para un solo método específico no debe ser tan mala. Si no vale la pena tanto tiempo durante la vida útil del programa, mi recomendación es que sea sencillo y no incluya la pequeña optimización.
Jacob
Anote las subclases que anulan el método particular. @OverridesMethodX.
Realice el trabajo de reflexión necesario en la carga de clases (es decir, en un bloque static
) para que publique la información a través de un indicador booleano final. Luego, consulta la bandera donde y cuando la necesites.
La reflexión se puede utilizar para determinar si un método está anulado. El código es un poco complicado. Por ejemplo, debe tener en cuenta que tiene una clase de tiempo de ejecución que es una subclase de la clase que reemplaza el método.
Vas a ver las mismas clases de tiempo de ejecución una y otra vez. Por lo tanto, puede guardar los resultados del cheque en un WeakHashMap
incrustado en la Class
.
Vea mi código en java.awt.Component
trata con coalesceEvents
para ver un ejemplo.
Sé que esta es una pregunta un poco vieja, pero por el bien de otros googlers:
Se me ocurrió una solución diferente utilizando interfaces.
class FastSub extends Super {}
class SlowSub extends Super implements Super.LetMeHandleThis {
void doSomethingSlow() {
//not optimized
}
}
class Super {
static interface LetMeHandleThis {
void doSomethingSlow();
}
void doSomething() {
if (this instanceof LetMeHandleThis)
((LetMeHandleThis) this).doSomethingSlow();
else
doSomethingFast();
}
private final void doSomethingFast() {
//optimized
}
}
O al revés:
class FastSub extends Super implements Super.OptimizeMe {}
class SlowSub extends Super {
void doSomethingSlow() {
//not optimized
}
}
class Super {
static interface OptimizeMe {}
void doSomething() {
if (this instanceof OptimizeMe)
doSomethingFast();
else
doSomethingSlow();
}
private final void doSomethingFast() {
//optimized
}
void doSomethingSlow(){}
}
Yo no haría esto. Viola la encapsulación y cambia el contrato de lo que se supone que debe hacer tu clase sin que los implementadores lo sepan.
Sin embargo, si tienes que hacerlo, la mejor manera es invocar.
class.getMethod("myMethod").getDeclaringClass();
Si la clase que se devuelve es la tuya, entonces no se reemplaza; Si es algo más, esa subclase lo ha anulado. Sí, esto es un reflejo, pero sigue siendo bastante barato.
Sin embargo, me gusta su enfoque de método protegido. Eso se vería algo así:
public class ExpensiveStrategy {
public void expensiveMethod() {
// ...
if (employOptimization()) {
// take a shortcut
}
}
protected boolean employOptimization() {
return false;
}
}
public class TargetedStrategy extends ExpensiveStrategy {
@Override
protected boolean employOptimization() {
return true; // Now we can shortcut ExpensiveStrategy.
}
}
quizás haya una forma más limpia de hacerlo a través del patrón de estrategia , aunque no sé cómo se modelan el resto de su aplicación y los datos, pero parece que podría encajar.
De todos modos, me afectó cuando me enfrenté a un problema similar. Podría tener una heurística que decida qué estrategia utilizar según los datos que se procesarán.
Nuevamente, no tengo suficiente información sobre su uso específico para ver si esto es una exageración o no. Sin embargo, me abstendré de cambiar la firma de clase para dicha optimización específica. Por lo general, cuando siento la necesidad de ir contra la corriente, lo tomo como un canto que no había previsto un caso de esquina cuando diseñé la cosa y que debería refactorizarla a una solución más completa y más limpia.
sin embargo, tenga cuidado, tal refactorización, cuando se realiza únicamente por motivos de optimización, conduce casi inevitablemente al desastre. Si este es el caso, tomaría el enfoque reflexivo sugerido anteriormente. No altera el contrato de herencia y, cuando se realiza correctamente, solo debe hacerse una vez por subclase que lo requiera durante la vida útil de la aplicación.
private static boolean isMethodImplemented(Object obj, String name)
{
try
{
Class<? extends Object> clazz = obj.getClass();
return clazz.getMethod(name).getDeclaringClass().equals(clazz);
}
catch (SecurityException e)
{
log.error("{}", e);
}
catch (NoSuchMethodException e)
{
log.error("{}", e);
}
return false;
}