java - sirve - Entrevista: ¿Podemos instanciar una clase abstracta?
para que sirve una clase abstracta (15)
Aquí, estoy creando instancia de mi clase.
No, no estás creando la instancia de tu clase abstracta aquí. Más bien, está creando una instancia de una subclase anónima de su clase abstracta. Y luego está invocando el método en su referencia de clase abstracta que apunta al objeto de subclase .
Este comportamiento está claramente listado en JLS - Sección # 15.9.1 : -
Si la expresión de creación de instancia de clase termina en un cuerpo de clase, la clase que se está creando es una clase anónima. Entonces:
- Si T denota una clase, se declara una subclase directa anónima de la clase nombrada por T. Es un error en tiempo de compilación si la clase denotada por T es una clase final.
- Si T denota una interfaz, se declara una subclase directa anónima de Object 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 la clase.
- La clase que está siendo instanciada es la subclase anónima.
Énfasis 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í:
Cada vez 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 una referencia al objeto recién creado como resultado, el constructor indicado se procesa para inicializar el nuevo objeto mediante el siguiente procedimiento:
Puede leer sobre el procedimiento completo en el enlace que proporcioné.
Para ver prácticamente que la clase que se está creando es una subclase anónima , solo necesita compilar ambas clases. Supongamos que colocas esas clases en dos archivos diferentes:
My.java:
abstract class My {
public void myMethod() {
System.out.print("Abstract");
}
}
Poly.java:
class Poly extends My {
public static void main(String a[]) {
My m = new My() {};
m.myMethod();
}
}
Ahora, compila tus dos 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 que creaste usando el siguiente código:
new My() {};
Entonces, está claro que hay una clase diferente siendo instanciada. Es solo que a esa clase se le da un nombre solo después de la compilación por parte del compilador.
En general, todas las subclases anónimas en su clase serán nombradas de esta manera:
Poly$1.class, Poly$2.class, Poly$3.class, ... so on
Esos números denotan el orden en que esas clases anónimas aparecen en la clase adjunta.
El entrevistador preguntó: ¿Podemos instanciar una clase abstracta? Yo dije: No. Él me dijo: mal, podemos.
Discutí un poco sobre esto. Luego me dijo que probara esto usted mismo en su 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 clase abstracta. ¿Alguien por favor me puede explicar esto? ¿Realmente me equivoqué durante mi entrevista?
Es imposible crear una instancia de una clase abstracta. Lo que realmente puede hacer es implementar algunos métodos comunes en una clase abstracta y dejar que otros no se implementen (declarándolos abstractos) y dejar que el descendiente concreto los implemente según sus necesidades. Luego puede hacer una fábrica, que devuelve una instancia de esta clase abstracta (en realidad, su implementador). En la fábrica, a continuación, decide qué implementador elegir. Esto se conoce como un patrón de diseño de fábrica:
public abstract class AbstractGridManager {
private LifecicleAlgorithmIntrface lifecicleAlgorithm;
// ... more private fields
//Method implemented in concrete Manager implementors
abstract public Grid initGrid();
//Methods common to all implementors
public Grid calculateNextLifecicle(Grid grid){
return this.getLifecicleAlgorithm().calculateNextLifecicle(grid);
}
public LifecicleAlgorithmIntrface getLifecicleAlgorithm() {
return lifecicleAlgorithm;
}
public void setLifecicleAlgorithm(LifecicleAlgorithmIntrface lifecicleAlgorithm) {
this.lifecicleAlgorithm = lifecicleAlgorithm;
}
// ... more common logic and getters-setters pairs
}
El implementador concreto solo necesita implementar los métodos declarados como abstractos, pero tendrá acceso a la lógica implementada en esas clases en una clase abstracta, que no se declaran abstractos:
public class FileInputGridManager extends AbstractGridManager {
private String filePath;
//Method implemented in concrete Manager implementors
abstract public Grid initGrid();
public class FileInputGridManager extends AbstractGridManager {
private String filePath;
//Method implemented in concrete Manager implementors
abstract public Grid initGrid();
public Grid initGrid(String filePath) {
List<Cell> cells = new ArrayList<>();
char[] chars;
File file = new File(filePath); // for example foo.txt
// ... more logic
return grid;
}
}
Entonces, finalmente, la fábrica se ve algo como esto:
public class GridManagerFactory {
public static AbstractGridManager getGridManager(LifecicleAlgorithmIntrface lifecicleAlgorithm, String... args){
AbstractGridManager manager = null;
// input from the command line
if(args.length == 2){
CommandLineGridManager clManager = new CommandLineGridManager();
clManager.setWidth(Integer.parseInt(args[0]));
clManager.setHeight(Integer.parseInt(args[1]));
// possibly more configuration logic
...
manager = clManager;
}
// input from the file
else if(args.length == 1){
FileInputGridManager fiManager = new FileInputGridManager();
fiManager.setFilePath(args[0]);
// possibly more method calls from abstract class
...
manager = fiManager ;
}
//... more possible concrete implementors
else{
manager = new CommandLineGridManager();
}
manager.setLifecicleAlgorithm(lifecicleAlgorithm);
return manager;
}
}
El receptor de AbstractGridManager llamaría a los métodos sobre él y obtendría la lógica, implementada en el descensor concreto (y parcialmente en los métodos de clase abstractos) sin saber cuál es la implementación concreta que obtuvo. Esto también se conoce como inversión de control o inyección de dependencia.
Es un hecho bien establecido que abstract class
no puede ser instanciada como todos respondieron.
Cuando el programa define una clase anónima, el compilador crea una nueva clase con un nombre diferente (tiene el patrón EnclosedClassName$n
donde n
es el número de la clase anónima)
Entonces, si descompilas esta clase de Java, encontrarás el código de la siguiente manera:
mi clase
abstract class my {
public void mymethod()
{
System.out.print("Abstract");
}
}
poly $ 1.class (la clase generada de la "clase anónima")
class poly$1 extends my
{
}
ploly.cass
public class poly extends my
{
public static void main(String[] a)
{
my m = new poly.1(); // instance of poly.1 class NOT the abstract my class
m.mymethod();
}
}
Extender una clase no significa que estés creando una instancia de la clase. En realidad, en su caso, está creando una instancia de la subclase.
Estoy bastante seguro de que las clases abstractas no permiten iniciar. Entonces, yo diría que no: no se puede crear una instancia de una clase abstracta. Pero, puedes extenderlo / heredarlo.
No puedes instanciar directamente una clase abstracta. Pero esto no significa que no pueda obtener una instancia de clase (no en realidad una instancia de clase abstracta original) de manera indirecta. Quiero decir que no puede crear una instancia de la clase abstracta original, pero puede:
- Crear una clase vacía
- Heredarlo de clase abstracta
- Instanciar la clase derviada
Por lo tanto, obtiene acceso a todos los métodos y propiedades en una clase abstracta a través de la instancia de clase derivada.
La parte técnica ha sido bien cubierta en las otras respuestas, y termina principalmente en:
"Está equivocado, no sabe nada, pídale que se una a SO y que lo solucione todo :)"
Me gustaría abordar el hecho (que se ha mencionado en otras respuestas) de que esto podría ser una stress-question y es una herramienta importante para que muchos entrevistadores sepan más sobre usted y cómo reacciona ante situaciones difíciles e inusuales. Al darle códigos incorrectos, él probablemente quiso ver si se defendió. Para saber si tiene la confianza para enfrentar a sus adultos mayores en situaciones similares a esta.
PD: No sé por qué, pero tengo la sensación de que el entrevistador ha leído esta publicación.
Las clases abstractas no pueden ser instanciadas, pero pueden ser subclasificadas. Ver este enlace
El mejor ejemplo es
Aunque la clase Calender tiene un método abstracto getInstance () , pero cuando dices Calendar calc=Calendar.getInstance();
calc se refiere a la instancia de clase de la clase GregorianCalendar como "GregorianCalendar extiende el calendario "
El tipo interno anónimo infacto le permite crear una subclase sin nombre de la clase abstracta y una instancia de esto.
Lo anterior crea una instancia de una clase interna anónima que es una subclase de my
clase abstracta. No es estrictamente equivalente a crear una instancia de la clase abstracta. OTOH, cada instancia de subclase es una instancia de todas sus súper clases e interfaces, por lo que la mayoría de las clases abstractas se crean instancias de una de sus subclases concretas.
Si el entrevistador acaba de decir "mal!" Sin explicar, y dio este ejemplo, como un contraejemplo único, creo que no sabe de qué está hablando, sin embargo.
No, no podemos crear el objeto de la clase abstracta, pero crear la variable de referencia de la clase abstracta. La variable de referencia se utiliza para referirse a los objetos de las clases derivadas (subclases de la clase abstracta)
Aquí está el ejemplo que ilustra este concepto.
abstract class Figure {
double dim1;
double dim2;
Figure(double a, double b) {
dim1 = a;
dim2 = b;
}
// area is now an abstract method
abstract double area();
}
class Rectangle extends Figure {
Rectangle(double a, double b) {
super(a, b);
}
// override area for rectangle
double area() {
System.out.println("Inside Area for Rectangle.");
return dim1 * dim2;
}
}
class Triangle extends Figure {
Triangle(double a, double b) {
super(a, b);
}
// override area for right triangle
double area() {
System.out.println("Inside Area for Triangle.");
return dim1 * dim2 / 2;
}
}
class AbstractAreas {
public static void main(String args[]) {
// Figure f = new Figure(10, 10); // illegal now
Rectangle r = new Rectangle(9, 5);
Triangle t = new Triangle(10, 8);
Figure figref; // this is OK, no object is created
figref = r;
System.out.println("Area is " + figref.area());
figref = t;
System.out.println("Area is " + figref.area());
}
}
Aquí vemos que no podemos crear el objeto de tipo Figura, pero podemos crear una variable de referencia de tipo Figura. Aquí creamos una variable de referencia de tipo Figura y Figura La variable de referencia de clase se usa para referirse a los objetos de Clase Rectángulo y Triángulo.
No, no se puede crear una instancia de una clase abstracta. Creamos una instancia de la clase anónima. En la clase abstracta declaramos métodos abstractos y definimos métodos concretos únicamente.
Solo observaciones que podrías hacer:
- ¿Por qué
poly
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 instanciar una clase abstracta como esa, también podemos instanciar una interfaz ... raro ...
¿Podemos instanciar una clase abstracta?
No, no podemos. Lo que podemos hacer es crear una clase anónima (que es el tercer archivo) y crear una instancia.
¿Qué pasa con una instanciación súper clase?
La súper clase abstracta no es instanciada por nosotros sino por java.
EDITAR: pedirle 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
Usted puede simplemente responder, en una sola línea
No , nunca puedes instanciar la clase abstracta
Pero, el entrevistador todavía no está de acuerdo, entonces usted puede decirle
todo lo que puedes hacer es crear una clase anónima.
Y, según la clase Anónima, la clase declarada y instanciada en el mismo lugar / línea
Por lo tanto, es posible que al entrevistador le interese verificar su nivel de confianza y cuánto sabe acerca de los OOP.
= my() {};
significa que hay una implementación anónima, no una simple instanciación de un objeto, que debería haber sido: = my()
. Nunca puedes instanciar una clase abstracta.
Puedes decir:
no podemos crear una instancia de una clase abstracta, pero podemos usar una new
palabra clave para crear una instancia de clase anónima simplemente agregando {}
como cuerpo del implemento al final de la clase abstracta.
Respuesta técnica
Las clases abstractas no pueden ser instanciadas, esto es por definición y diseño.
Desde el JLS, Capítulo 8. Clases:
Una clase nombrada puede ser declarada abstracta (§8.1.1.1) y debe declararse abstracta si se implementa de manera incompleta; tal clase no puede ser instanciada, pero puede ser extendida por subclases.
Desde JSE 6 java doc para Classes.newInstance ():
InstantiationException: si esta Clase representa una clase abstracta, una interfaz, una clase de matriz, un tipo primitivo o vacío; o si la clase no tiene constructor nulo; o si la instanciación falla por alguna otra razón.
Por supuesto, puede crear una instancia de una subclase concreta de una clase abstracta (incluida una subclase anónima) y también realizar una transmisión de tipo de una referencia de objeto a un tipo abstracto.
Un ángulo diferente en esto - Juego en equipo e inteligencia social:
Este tipo de malentendido técnico ocurre con frecuencia en el mundo real cuando tratamos con tecnologías complejas y especificaciones legalistas.
Las "habilidades de las personas" pueden ser más importantes aquí que las "habilidades técnicas". Si intentas probar tu lado del argumento de manera competitiva y agresiva, entonces podrías ser teóricamente correcto, pero también podrías hacer más daño al tener una pelea / dañar "cara" / crear un enemigo de lo que vale. Sea reconciliatorio y comprensivo en la resolución de sus diferencias. Quién sabe, tal vez tengas "razón" pero ¿estás trabajando con significados ligeramente diferentes para los términos?
Quién sabe, aunque no es probable, es posible que el entrevistador haya introducido deliberadamente un pequeño conflicto / malentendido para ponerlo en una situación desafiante y ver cómo se comporta emocional y socialmente. Sea amable y constructivo con sus colegas, siga los consejos de los adultos mayores y siga adelante después de la entrevista para resolver cualquier problema / malentendido, por correo electrónico o por teléfono. Demuestra que estás motivado y orientado al detalle.
Sobre clases abstractas
- No se puede crear objeto de una clase abstracta
- Puede crear variables (puede comportarse como tipos de datos)
- Si un niño no puede anular al menos un método abstracto del padre, entonces el niño también se vuelve abstracto
- Las clases de resumen son inútiles sin clases de niños.
El propósito de una clase abstracta es comportarse como una base. En la jerarquía de herencia verás clases abstractas hacia la parte superior.