resueltos polimorfismo interfaces herencia ejercicios ejemplos clases clase anonimas anonima abstracta java anonymous-class anonymous-inner-class cyclic-reference

polimorfismo - interfaces en java ejemplos



¿Es incorrecta la dependencia cíclica entre la clase anónima y la clase padre? (5)

¿Está bien o no?

Esto está completamente bien.

threshold es un campo, por lo que puede ser referenciado desde una clase anónima sin ningún problema. (Si el threshold hubiera sido una variable local, tendría que haber sido (efectivamente) final).

Las dependencias cíclicas entre clases son comunes y cuando el gráfico de dependencia es pequeño (como en este caso) no plantea ningún problema. El hecho de que tu LinkedHashMap sea ​​una clase anónima no importa aquí.

¿Será bien reclamado por el recolector de basura?

Lo único a tener en cuenta con respecto a las fugas de memoria + clases internas es que una clase interna (no estática) tiene una referencia implícita a su objeto adjunto. Esto significa que si creas muchísimas instancias de la clase interna, no puedes esperar que las instancias de los objetos de la clase externa se recojan.

Lo que eso significa en este caso es que si filtra referencias al mapa history , las instancias de Example no se eliminarán.

Notas relacionadas:

  • Teniendo en cuenta que estás usando synchronizedMap , parece que estás trabajando en un programa de multiproceso. Si este es el caso, debe tener cuidado con los problemas de sincronización y visibilidad para el campo de threshold .

  • Si es posible, intenta hacer que el campo del threshold definitivo.

  • Otra opción sería crear una clase con nombre para tu LinkedHashMap e incluir un threshold como campo en esa clase.

Tengo el siguiente fragmento de código:

public class Example { private Integer threshold; private Map<String, Progress> history; protected void activate(ComponentContext ctx) { this.history = Collections.synchronizedMap(new LinkedHashMap<String, Progress>() { @Override protected boolean removeEldestEntry(Map.Entry<String, Progress> entry) { return size() > threshold; } }); } }

Theres es una dependencia cíclica entre la clase LinkedHashMap anónima y la clase Example . ¿Está bien o no? Por qué no? ¿Será bien reclamado por el recolector de basura?


Cada vez que crea una instancia de una clase interna no estática (ya sea nombrada o anónima), la instancia de esta clase interna obtiene automáticamente una referencia a la instancia de la clase primaria que lo contiene.

Lo anterior significa que si la clase externa también contiene una referencia a la clase interna no estática (como es el caso en su código), entonces existe una dependencia cíclica entre las instancias de la clase externa y la clase interna no estática (nuevamente, tanto nombrados como anónimos).

La única pregunta real en esta configuración es si su uso de esta referencia cruzada existente es legítimo. En su caso específico, no veo ningún problema: la clase interna no estática utiliza una variable de instancia de la clase externa envolvente. Me parece un kosher.

En esta situación, la pérdida de memoria usualmente ocurre cuando una referencia a la instancia de la clase interna se pasa fuera de la clase externa (lo cual es comúnmente el caso con varios Listeners ), ya que esta instancia tiene una referencia a la instancia de la clase externa, La clase externa no puede ser recogida de basura. Sin embargo, no creo que se pueda producir una pérdida de memoria si solo se hace una referencia cruzada entre las clases externas y las internas, se recolectarán juntos.


De todos modos, tiene esta dependencia, porque cada objeto de una clase interna anónima tiene una referencia implícita al objeto de una clase envolvente. Java está diseñado de esa manera, y las clases internas anidadas tienen esta referencia por una razón, por lo que desde el punto de vista de las especificaciones del lenguaje, esto se compila y se ve perfectamente normal.

Con respecto a la (ausencia de) "olor a diseño", si este objeto de clase anónima está completamente encapsulado en la clase Example , no tiene un significado distintivo sin su contexto adjunto, y no se filtra en ningún lugar fuera de la clase Example , no hay nada de malo en los campos de referencia de la clase de clausura. Simplemente usas esta clase interna para agrupar alguna lógica.

Sin embargo, si este objeto se filtra fuera del objeto que lo contiene (por ejemplo, lo devuelve a través del captador), debe prohibirlo o refactorizarlo en una clase interna estática que reciba el threshold como parámetro. Este objeto interno contiene referencia al objeto que lo encierra y puede evitar que se mueva de GC, lo que provoca una pérdida de memoria.


La dependencia cíclica no es mala en sí misma, sin embargo, puede causar algunas pérdidas de memoria insospechadas.

Tomando su ejemplo como está, está bien ahora mismo ya que hace lo que usted quiere que haga.

Sin embargo, si usted o alguien más modifica su código para exponer su privado:

private Map<String, Progress> history;

Entonces usted puede tener problemas. Lo que sucederá es que también pasará la referencia a la clase Ejemplo, ya sea con intención o no, ya que su clase interna tiene una referencia implícita a ella.

No puedo darte una cita directa en este momento, pero Steve McConnell en su código completo está llamando a las dependencias cíclicas un anti-patrón. Puedes leer allí o supongo que google para ello, para leer sobre esto con gran detalle.

Otro problema que se me ocurre es que la dependencia cíclica es bastante difícil de probar por unidad, ya que está creando un alto nivel de acoplamiento entre objetos.

En general, debe evitar la dependencia circular a menos que tenga una buena razón para no hacerlo, como implementar la lista enlazada circular.


No me gusta tu solución (incluso si estoy de acuerdo, esto podría funcionar):

  1. el ejemplo de su clase debería implementar Map o extender LinkedHashMap porque el umbral variable de la instancia está definido allí y refina el concepto de LinkedHashMap con su propia definición.

  2. el ejemplo de su clase NO debe implementar Map o extender LinkedHashMap porque el método de activación no refina LinkedHashMap ni Map, sino que utiliza conceptos de Maps.

1 + 2 => problema de concepción.