Marker Interfaces en Java?
design-patterns marker-interfaces (9)
Me enseñaron que la interfaz Marker en Java es una interfaz vacía y se utiliza para indicar al compilador o JVM que los objetos de la clase que implementa esta interfaz deben tratarse de una manera especial, como la serialización, la clonación, etc.
Pero últimamente aprendí que en realidad no tiene nada que ver con el compilador o la JVM. Por ejemplo, en el caso de la interfaz Serializable
, el método writeObject(Object)
de ObjectOutputStream
hace algo parecido a instanceOf Serializable
para detectar si la clase implementa Serializable
y arroja NotSerializableException
consecuencia. Todo se maneja en el código y parece ser un patrón de diseño, así que creo que podemos definir nuestras propias interfaces de marcador.
Ahora mis dudas:
¿Es incorrecta la definición de una interfaz de marcador mencionada anteriormente en el primer punto? ¿Cómo podemos definir una interfaz Marker entonces?
Y en lugar de utilizar el operador
instanceOf
, ¿por qué el método no puede ser algo así comowriteObject(Serializable)
para que haya una comprobación de tipos en tiempo de compilación en lugar de tiempo de ejecución?¿Cómo son las anotaciones mejores que las interfaces de marcador?
- ¿Es incorrecta la definición de una interfaz de marcador mencionada anteriormente en el primer punto? - Es correcto en las partes que (1) una interfaz de marcador debe estar vacía, y (2) su implementación implica un tratamiento especial de la clase implementadora. La parte que es incorrecta es que implica que JVM o el compilador tratarán los objetos de esa clase de forma diferente: tiene razón al observar que es el código de la biblioteca de clases Java el que trata estos objetos como clonables, serializables, etc. nada que ver con el compilador o la JVM.
- en lugar de usar el operador instanceOf, ¿por qué el método no puede ser algo así como
writeObject(Serializable)
para que haya una comprobación de tipos en tiempo de compilación ? Esto le permite evitar contaminar el código con el nombre de la interfaz cuando un "Object
simple" es necesario. Por ejemplo, si crea una clase que necesita ser serializable y tiene miembros de objeto, se lo forzará a hacer fundido o a hacer que sus objetos seanSerializable
en tiempo de compilación. Esto es inconveniente, porque la interfaz carece de cualquier funcionalidad. - ¿Cómo anotaciones son mejores que las interfaces de Marker? - Le permiten lograr el mismo propósito de transmitir metadatos sobre la clase a sus consumidores sin crear un tipo separado para ella. Las anotaciones son más potentes, también, lo que permite a los programadores pasar información más sofisticada a clases que la "consuman".
No tiene nada que ver (necesariamente) con la JVM y los compiladores, tiene algo que ver con cualquier código que esté interesado y esté probando para una interfaz de marcador determinada.
Es una decisión de diseño y está hecha por una buena razón. Vea la respuesta de Audrius Meškauskas.
Con respecto a este tema en particular, no creo que sea una cuestión de ser mejor o peor. La interfaz del marcador está haciendo lo que se supone que hace bien.
El objetivo principal de las interfaces de marcadores es crear tipos especiales donde los tipos en sí mismos no tengan un comportamiento propio.
public interface MarkerEntity {
}
public boolean save(Object object) throws InvalidEntityFoundException {
if(!(object instanceof MarkerEntity)) {
throw new InvalidEntityFoundException("Invalid Entity Found, can''t be saved);
}
return db.save(object);
}
Aquí el método save se asegura de que solo se guarden los objetos de las clases que implementan la interfaz MarkerEntity, para otros tipos se genera InvalidEntityFoundException. Entonces, aquí la interfaz MarkerEntity está definiendo un tipo que agrega un comportamiento especial a las clases que lo implementan.
Aunque las anotaciones también se pueden usar ahora para marcar las clases de algunos tratamientos especiales, pero las anotaciones de marcadores reemplazan al patrón de nomenclatura no para las interfaces de Marker.
Pero las anotaciones de marcador no pueden reemplazar completamente las interfaces de marcador porque; Las interfaces de marcador se usan para definir el tipo (como ya se explicó anteriormente) donde las anotaciones de marcador no lo hacen.
En primer lugar, argumentaría que Serializable y Cloneable son malos ejemplos de interfaces de marcadores. Claro, son interfaces con métodos, pero implican métodos, como writeObject(ObjectOutputStream)
. (El compilador creará un writeObject(ObjectOutputStream)
para usted si no lo anula, y todos los objetos ya tienen clone()
, pero el compilador volverá a crear un método real clone()
para usted pero con advertencias. estos son casos de borde extraño que realmente no son buenos ejemplos de diseño.)
Las interfaces de marcador generalmente se usan con uno de dos propósitos:
1) Como un atajo para evitar un tipo excesivamente largo, que puede ocurrir con muchos genéricos. Por ejemplo, supongamos que tienes esta firma de método:
public void doSomething(Foobar<String, Map<String, SomethingElse<Integer, Long>>>) { ... }
Es complicado y molesto escribir y, lo que es más importante, difícil de entender. Considera esto en su lugar:
public interface Widget extends Foobar<String, Map<String, SomethingElse<Integer, Long>>> { }
Entonces su método se ve así:
public void doSomething(Widget widget) { ... }
No solo es más claro, sino que ahora puedes hacer Javadoc en la interfaz del widget, y también es más fácil buscar todas las ocurrencias en tu código de Widget.
2) Las interfaces de marcadores también se pueden usar para sortear la falta de tipos de intersección de Java. Con una interfaz de marcador, puede requerir que algo sea de dos tipos diferentes, como en una firma de método. Supongamos que tiene algún widget de interfaz en su aplicación, como describimos anteriormente. Si tiene un método que requiere un Widget que también le permite iterar sobre él (está artificial, pero trabaje conmigo aquí), su única buena solución es crear una interfaz de marcador que amplíe ambas interfaces:
public interface IterableWidget extends Iterable<String>, Widget { }
Y en tu código:
public void doSomething(IterableWidget widget) {
for (String s : widget) { ... }
}
La interfaz Marker en Java es una interfaz sin campos ni métodos. En palabras simples, la interfaz vacía en java se llama interfaz de marcador. Ejemplo de interfaz de marcador es la interfaz Serializable, Cloneable y Remote. Estos se utilizan para indicar algo al compilador o JVM. Por lo tanto, si JVM ve una interfaz de marcado de implementación de Clase, realiza algunas operaciones especiales en ella, de forma similar si JVM ve que una Clase está implementando Clonación, realiza alguna operación para admitir la clonación. Lo mismo es cierto para RMI y la interfaz remota. En resumen, la interfaz Marker es para indicar o señalar o mandar al Compilador o JVM.
No es posible aplicar Serializable
en writeObject
porque los hijos de la clase no serializable pueden ser serializables, pero las instancias pueden reenviarse a la clase principal. Como resultado, mantener una referencia a algo no serializable (como Object
) no significa que la instancia referida realmente no se pueda serializar. Por ejemplo, en
Object x = "abc";
if (x instanceof Serializable) {
}
la clase padre ( Object
) no es serializable y se inicializaría usando su constructor sin parámetros. El valor al que hace referencia x
, String
, es serializable y se ejecutaría la sentencia condicional.
Si una interfaz no contiene ningún método e implícitamente esa interfaz si nuestro objeto tendrá alguna capacidad, ese tipo de interfaces se denominan marcadores de marcador.
a / Una interfaz de marcador como su nombre sugiere existe solo para notificar a cualquier cosa que sepa sobre ella que una clase declara algo. Cualquier cosa puede ser las clases JDK para la interfaz Serializable
, o cualquier clase que escribas para una personalizada.
b / Si se trata de una interfaz de marcador, no debe implicar la existencia de ningún método; sería mejor incluir el método implícito en la interfaz. Pero puedes decidir diseñarlo como quieras si sabes por qué lo necesitas
c / Hay poca diferencia entre una interfaz vacía y una anotación que no usa ningún valor o parámetro. Pero la diferencia está ahí: una anotación puede declarar una lista de claves / valores que serán accesibles en tiempo de ejecución.
a. Siempre los he visto como un patrón de diseño y nada JVM-Special. He usado ese patrón en varias situaciones.
do. Creo que usar Anotaciones para marcar algo es una mejor solución que usar interfaces de marcador. Simplemente porque las interfaces están en primer lugar destinadas a definir interfaces comunes de tipos / clases. Ellos son parte de la jerarquía de clases.
Las anotaciones están destinadas a proporcionar Meta-Informations to Code, y creo que ese marcador son metainformaciones. Entonces son exactamente para ese caso de uso.