Entrevista: ¿Podemos instanciar una clase abstracta?

El entrevistador preguntó: ¿Podemos crear una instancia de una clase abstracta? Dije: No. Él me dijo: Mal, podemos.

Discutí un poco sobre esto. Luego me dijo que probara esto en tu 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 método de llamada de clase abstracta. ¿Alguien puede explicarme esto? ¿Estaba realmente equivocado 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á invocando el método en su referencia de clase abstracta apuntando al objeto de la subclase .

Este comportamiento está claramente enumerado 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 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 comstackció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 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 instancia de clase.
  • La clase que se crea una instancia 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 statement de eso aquí:

Cada vez que se crea una nueva instancia de clase, se 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 usando el siguiente procedimiento:

Puede leer sobre el procedimiento completo en el enlace que proporcioné.


Para prácticamente ver que la clase que se está instanciando es una Subclase Anónima , solo necesita comstackr ambas clases. Supongamos que coloca 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, comstack 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 comstackdor correspondiente a la subclase anónima que instanciaste usando el siguiente código:

 new My() {}; 

Entonces, está claro que hay una clase diferente siendo instanciada. Es solo que, esa clase recibe un nombre solo después de la comstackción del comstackdor.

En general, todas las subclases anónimas en su clase se nombrarán 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.

Lo anterior crea 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 en sí misma. 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 instancian instanciando una de sus subclases concretas.

Si el entrevistador acaba de decir “¡mal!” sin explicar, y dio este ejemplo, como contraejemplo único, creo que él no sabe de lo que está hablando, sin embargo.

= my() {}; significa que hay una implementación anónima, no una instanciación simple de un objeto, que debería haber sido: = my() . Nunca puedes instanciar una clase abstracta.

Solo observaciones que podrías hacer:

  1. ¿Por qué poly extiende my ? Esto es inútil …
  2. ¿Cuál es el resultado de la comstackción? Tres archivos: my.class , poly.class y poly$1.class
  3. Si podemos crear una instancia de una clase abstracta como esa, también podemos instanciar una interfaz … extraño …

¿Podemos instanciar 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.

¿Qué tal una instanciación de superclase?

La súper clase abstracta no es instanciada por nosotros, sino por 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()); } 

salida es:

 false class my$1 class my$2 

Simplemente puede responder, en una sola línea

No , nunca puedes instanciar la clase abstracta

Pero, entrevistador todavía no está de acuerdo, entonces usted puede decirle

Todo lo que puedes hacer es crear una clase anónima.

Y, de acuerdo con la clase Anónima, clase declarada e instancia en el mismo lugar / línea

Por lo tanto, es posible que el entrevistador esté interesado en verificar su nivel de confianza y cuánto sabe acerca de los OOP.

La parte técnica ha sido bien cubierta en las otras respuestas, y principalmente termina en:
“Está equivocado, no sabe nada, pídele que se una a SO y aclare todo :)”

Quisiera abordar el hecho (que se ha mencionado en otras respuestas) de que esta podría ser una pregunta de estrés y es una herramienta importante para que muchos entrevistadores sepan más sobre usted y cómo reactjs ante situaciones difíciles e inusuales. Al darte códigos incorrectos, probablemente quería ver si respondiste. Para saber si tiene la confianza para enfrentarse a sus superiores 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 se pueden crear instancias, pero se pueden subclasificar. 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 extends Calendar

De hecho, el tipo interno anónimo le permite crear una subclase sin nombre de la clase abstracta y una instancia de esto.

Respuesta técnica

Las clases abstractas no se pueden instanciar, esto es por definición y diseño.

Del JLS, Capítulo 8. Clases:

Una clase con nombre puede declararse abstracta (§8.1.1.1) y debe declararse como abstracta si no se implementa por completo. dicha clase no se puede instanciar, pero se puede ampliar por subclases.

De 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 nulo; o si la clase no tiene constructor nullary; 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 conversión de tipo de objeto a un tipo abstracto.

Un ángulo diferente en esto: Teamplay y Social Intelligence:

Este tipo de malentendido técnico ocurre con frecuencia en el mundo real cuando tratamos con tecnologías complejas y especificaciones legalistas.

“Habilidades de personas” puede ser más importante aquí que “Habilidades técnicas”. Si competitiva y agresivamente intentas probar tu lado del argumento, entonces podrías tener la razón teórica, pero también podrías hacer más daño al tener una “cara” / pelea dañina / creando un enemigo de lo que vale. Sé conciliador y comprensivo al resolver tus diferencias. ¿Quién sabe? ¿Tal vez usted “tiene razón” pero está 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 difícil y ver cómo se comporta emocional y socialmente. Sea cordial y constructivo con sus colegas, siga los consejos de las personas mayores y realice el seguimiento después de la entrevista para resolver cualquier desafío / malentendido, por correo electrónico o llamada telefónica. Muestra que estás motivado y orientado a los detalles.

Es un hecho bien establecido que abstract class no puede ser instanciada ya que todos respondieron.

Cuando el progtwig define una clase anónima, el comstackdor realmente crea una nueva clase con un nombre diferente (tiene el patrón EnclosedClassName$n donde n es el número de clase anónimo)

Entonces, si descomstacks 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(); } } 

No, no puede crear instancias de una clase abstracta. Instalamos solo clases anónimas. En la clase abstracta, declaramos métodos abstractos y solo definimos métodos concretos.

Acerca de las clases abstractas

  • No se puede crear el 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 abstractas son inútiles sin clases de niños

El objective de una clase abstracta es comportarse como una base. En la jerarquía de herencia verás clases abstractas hacia la parte superior.

Puedes decir:
no podemos instanciar una clase abstracta, pero podemos usar una palabra clave new para crear una instancia de clase anónima simplemente agregando {} como cuerpo del apero al final de la clase abstracta.

La extensión de una clase no significa que estés instanciando la clase. En realidad, en tu caso estás creando una instancia de la subclase.

Estoy bastante seguro de que las clases abstractas no permiten iniciar. Entonces, diría que no: no puedes instanciar una clase abstracta. Pero, puedes extenderlo / heredarlo.

No puedes instanciar directamente una clase abstracta. Pero eso no significa que no pueda obtener una instancia de clase (no en realidad una instancia de la clase abstracta original) indirectamente. Quiero decir que no puedes instanciar la clase abstracta de orginial, pero puedes:

  1. Crea una clase vacía
  2. Heredarlo de la clase abstracta
  3. Crear una instancia de la clase dervied

De modo que tiene acceso a todos los métodos y propiedades en una clase abstracta a través de la instancia de clase derivada.

Es imposible instanciar 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 (declarando que son abstractos) y dejar que el descensor concreto los implemente en función de sus necesidades. Entonces puedes hacer una fábrica, que devuelve una instancia de esta clase abstracta (en realidad su implementador). En la fábrica, usted 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 declara abstracta:

 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 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 así:

 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 los métodos sobre él y obtendrá la lógica, implementada en el descifrador concreto (y parcialmente en los métodos de clase abstracta) sin saber cuál es la implementación concreta que obtuvo. Esto también se conoce como inversión de control o dependency injection.

No, no podemos crear el objeto de la clase abstracta, sino crear la variable de referencia de la clase abstracta. La variable de referencia se usa para referirse a los objetos de clases derivadas (Sub clases de 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 Rectangular y Triángulo.

    Intereting Posts