¿Podemos crear una instancia de una clase abstracta?
Durante una de mis entrevistas, me preguntaron "¿Si podemos crear una instancia de una clase abstracta?"
Mi respuesta fue "No, no podemos". Pero el entrevistador me dijo: "Mal, podemos".
Discutí un poco sobre esto. Luego me dijo que lo probara yo mismo en casa.
abstract class my {
public void mymethod() {
System.out.print("Abstract");
}
}
class poly {
public static void main(String a[]) {
my m = new my() {};
m.mymethod();
}
}
Aquí, estoy creando una instancia de mi clase y llamando al método de la clase abstracta. ¿Alguien puede explicarme esto? ¿Realmente me equivoqué durante mi entrevista?
Aquí, estoy creando una instancia de mi clase.
No, no estás creando la instancia de tu clase abstracta aquí. Más bien, estás creando una instancia de una subclase anónima de tu clase abstracta. Y luego estás invocando el método en tu referencia de clase abstracta que apunta al objeto de subclase .
Este comportamiento se enumera claramente en JLS - Sección # 15.9.1 : -
Si la expresión de creación de instancia de clase termina en un cuerpo de clase, entonces la clase de la que se crea una instancia es una clase anónima. Entonces:
- Si T denota una clase, entonces se declara una subclase directa anónima de la clase nombrada por T. Es un error en tiempo de compilación si la clase indicada por T es una clase final.
- Si T denota una interfaz, entonces se declara una subclase directa anónima de Objeto que implementa la interfaz nombrada por T.
- En cualquier caso, el cuerpo de la subclase es el ClassBody dado en la expresión de creación de la instancia de clase.
- La clase de la que se crea una instancia es la subclase anónima.
El énfasis es mío.
Además, en JLS - Sección # 12.5 , puede leer sobre el Proceso de creación de objetos . Citaré una declaración de eso aquí: -
Siempre que se crea una nueva instancia de clase, se le asigna espacio de memoria con espacio para todas las variables de instancia declaradas en el tipo de clase y todas las variables de instancia declaradas en cada superclase del tipo de clase, incluidas todas las variables de instancia que pueden estar ocultas.
Justo antes de que se devuelva como resultado una referencia al objeto recién creado, se procesa el constructor indicado para inicializar el nuevo objeto mediante el siguiente procedimiento:
Puede leer sobre el procedimiento completo en el enlace que le proporcioné.
Para ver prácticamente que la clase de la que se está creando una instancia es una Subclase anónima , solo necesita compilar ambas clases. Supongamos que pones esas clases en dos archivos diferentes:
Mi.java:
abstract class My {
public void myMethod() {
System.out.print("Abstract");
}
}
Poli.java:
class Poly extends My {
public static void main(String a[]) {
My m = new My() {};
m.myMethod();
}
}
Ahora, compila ambos archivos fuente:
javac My.java Poly.java
Ahora, en el directorio donde compiló el código fuente, verá los siguientes archivos de clase:
My.class
Poly$1.class // Class file corresponding to anonymous subclass
Poly.class
Ver esa clase - Poly$1.class
. Es el archivo de clase creado por el compilador correspondiente a la subclase anónima de la que creaste una instancia usando el siguiente código:
new My() {};
Entonces, está claro que se está creando una instancia de una clase diferente. Es solo que esa clase recibe un nombre solo después de que el compilador la compila.
En general, todas las subclases anónimas de su clase se nombrarán de esta manera:
Poly$1.class, Poly$2.class, Poly$3.class, ... so on
Esos números indican el orden en que aparecen esas clases anónimas en la clase adjunta.
Lo anterior crea una instancia de una clase interna anónima que es una subclase de la my
clase abstracta. No es estrictamente equivalente a crear una instancia de la propia clase abstracta. OTOH, cada instancia de subclase es una instancia de todas sus superclases e interfaces, por lo que la mayoría de las clases abstractas se crean instancias al crear una instancia de una de sus subclases concretas.
Si el entrevistador simplemente dijera "¡mal!" sin dar explicaciones, y dio este ejemplo, como un contraejemplo único, aunque creo que no sabe de lo que está hablando.
= my() {};
significa que hay una implementación anónima, no una simple creación de instancias de un objeto, que debería haber sido: = my()
. Nunca puedes crear una instancia de una clase abstracta.
Solo observaciones que podrías hacer:
- ¿Por qué
poly
se extiendemy
? Esto es inútil... - ¿Cuál es el resultado de la compilación? Tres archivos:
my.class
,poly.class
ypoly$1.class
- Si podemos crear una instancia de una clase abstracta como esa, también podemos crear una instancia de una interfaz... raro...
¿Podemos crear una instancia de una clase abstracta?
No, no podemos. Lo que podemos hacer es crear una clase anónima (ese es el tercer archivo) y crear una instancia de ella.
¿Qué pasa con una creación de instancias de superclase?
La superclase abstracta no la creamos nosotros , sino Java.
EDITAR: Pídale que pruebe esto
public static final void main(final String[] args) {
final my m1 = new my() {
};
final my m2 = new my() {
};
System.out.println(m1 == m2);
System.out.println(m1.getClass().toString());
System.out.println(m2.getClass().toString());
}
la salida es:
false
class my$1
class my$2