una - regresar a la ventana anterior java
¿Cómo restringir esa subclase no puede ser genérico? (3)
Error de tiempo de compilación: la clase genérica no puede subclase java.lang.Throwable
public class TestGenericClass<E> extends Exception {
/*Above line will give compile error, the generic class TestGenericClass<E> may
not subclass java.lang.Throwable*/
public TestGenericClass(String msg) {
super(msg);
}
}
El error anterior a la compilación es por la razón dada en § jls-8.1.2 como se muestra a continuación, y se explica en esta pregunta :
Es un error en tiempo de compilación si una clase genérica es una subclase directa o indirecta de Throwable (§11.1.1).
Esta restricción es necesaria ya que el mecanismo de captura de la Máquina Virtual de Java solo funciona con clases no genéricas.
Pregunta:
¿Cómo se restringe que la subclase de
java.lang.Throwable
no sea genérica?O una pregunta más genérica será, ¿cómo restringir que las subclases de cualquier clase no puedan ser genéricas?
¿Cómo se restringe que la subclase de java.lang.Throwable no sea genérica?
Así es como el compilador OpenJDK realiza el control:
import com.sun.tools.javac.code.Symbol.*;
private void attribClassBody(Env<AttrContext> env, ClassSymbol c) {
....
// Check that a generic class doesn''t extend Throwable
if (!c.type.allparams().isEmpty() && types.isSubtype(c.type, syms.throwableType))
log.error(tree.extending.pos(), "generic.throwable");
Como puede ver, el tipo prohibido está algo codificado, por lo que no puede usar la misma técnica para su clase personalizada sin la personalización del código del compilador.
Si está dispuesto a retrasar el error hasta el tiempo de ejecución, puede utilizar el uso de la reflexión en el constructor (es) de la superclase para ver si la subclase declara cualquier parámetro de tipo.
public class Example {
public static class ProhibitsGenericSubclasses {
public ProhibitsGenericSubclasses() {
if (getClass().getTypeParameters().length > 0)
throw new AssertionError("ProhibitsGenericSubclasses prohibits generic subclasses (see docs)");
}
}
public static class NonGenericSubclass extends ProhibitsGenericSubclasses {}
public static class GenericSubclass<T> extends ProhibitsGenericSubclasses {}
public static void main(String[] args) {
System.out.println(new NonGenericSubclass());
System.out.println(new GenericSubclass<Object>());
}
}
Este código imprime
Example$NonGenericSubclass@15db9742
Exception in thread "main" java.lang.AssertionError: ProhibitsGenericSubclasses prohibits generic subclasses (see docs)
at Example$ProhibitsGenericSubclasses.<init>(Example.java:12)
at Example$GenericSubclass.<init>(Example.java:17)
at Example.main(Example.java:21)
Si desea prohibir los parámetros de tipo de todas las clases en la jerarquía, no solo la clase más derivada, deberá subir la jerarquía utilizando Class#getSuperclass()
.
¿Cómo se restringe que la subclase de java.lang.Throwable no sea genérica?
Esta fue una decisión para escribir un caso especial en el compilador. La razón por la cual se detalla en esta pregunta . Básicamente, esto tiene que ver con un tipo que sea reificable . Puedes leer sobre este término aquí . En resumen, un tipo es reificable si su tipo está completamente disponible en el momento de la compilación. Los tipos genéricos, por ejemplo, no son reificables, porque sus tipos se eliminan por borrado de tipo. Los objetos que aparecen en un bloque catch
deben ser reificables .
O una pregunta más genérica, ¿cómo restringir que las subclases de una clase no puedan ser genéricas?
Bueno, hay algunas opciones ...
Actualmente, no hay ninguna opción dentro de los límites normales de Java para hacer esto. No tiene algún tipo de implementación final
que impida la aplicación de genéricos a las subclases. Lo más cercano que puede llegar a esto, como se explica en los comentarios, es extender el compilador y agregar una regla específicamente para su clase. Esta solución envía escalofríos por mi espina dorsal. Esquivarlo. Significa que su código solo se comportará con su versión de Java, y que cualquier otra persona que quiera usar su código tendrá que instalar la misma versión.
Obviamente, la otra opción es extender Throwable
, pero esto realmente no es una buena idea. Agrega una gran cantidad de funcionalidades a su clase, y agrega muchos métodos nuevos a la interfaz de su clase, que nunca usará. Desde el punto de vista de OOP, está sacrificando la integridad de su clase por el beneficio de tener esta característica.