¿Podemos instanciar una clase abstracta?


574

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 probara esto 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? ¿Estaba realmente equivocado durante mi entrevista?


2
Aunque solo está ligeramente relacionado, quizás se pueda crear una instancia de una clase abstracta en C ++: si deriva una clase no abstracta Bde una abstracta A, durante la parte de construcción de Binstancia, que consiste en ejecutar Ael constructor, el tipo de tiempo de ejecución del objeto es en realidad A. Sin embargo, solo temporal.
Vlad

8
@jWeavers: El ejemplo que ha dado está totalmente equivocado. Deberías haberle preguntado "entonces, para qué sirve la clase abstracta". Si lo está extendiendo, ¿por qué está creando una instancia de la clase extendida? Es un objeto completamente nuevo, donde terminas sin datos ...
Lemon Juice

3
¡O puede ser que el entrevistador quisiera comprobar qué tan seguro está de su declaración con respecto a lo que propuso!
Sid

55
Él te mintió. Dejó caer la pelota cuando no pudo señalar que no es lo que hace este código y explicar qué son las subclases anónimas. Probablemente ya lo sabía y quería ver si lo sabías.
candied_orange

2
Esto no fue un concurso de preguntas, sino una entrevista de trabajo, ¿verdad? Entonces, ¿qué pasa si Java o C ++ permiten instanciar clases abstractas? No lo harías, porque no es algo inteligente. En Objective-C, las clases abstractas solo son abstractas por convención, e instanciarlas es un error.
gnasher729

Respuestas:


723

Aquí estoy creando una instancia de mi clase

No, no está creando la instancia de su clase abstracta aquí. Por el contrario, 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 apuntando 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, entonces la clase que se instancia 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 anónima directa 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 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í:

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á instanciando es una Subclase anónima , solo necesita compilar 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, 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 que creó mediante el siguiente código:

new My() {};

Entonces, está claro que hay una clase diferente siendo instanciada. Es solo eso, esa clase recibe un nombre solo después de la compilación por parte del compilador.

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 denotan el orden en que esas clases anónimas aparecen en la clase adjunta.


173
@coders. La respuesta exacta es: - No puede crear una instancia de su clase abstracta, sin embargo, puede crear una instancia de una subclase concreta de su clase abstracta.
Rohit Jain

17
En una línea puede decir: - Nunca puede crear una instancia de una clase abstracta. Ese es el propósito de una clase abstracta.
Rahul Tripathi

66
Parece que el entrevistador estaba más interesado en su respuesta que en la suya ...
Neil T.

77
Según otro comentario (con una referencia JLS ), "Se dice que un objeto es una instancia de su clase y de todas las superclases de su clase", por lo tanto, ¿no estamos creando técnicamente una instancia de la clase abstracta aquí? es decir, instanciar la clase abstracta?
arshajii

66
@ ARS Yo diría que hay una diferencia entre ser un instance ofy instantiating. Solo crea una instancia de una clase, mientras que el objeto que crea puede ser una instancia de varias clases debido a la herencia.
Simon Forsberg

90

Lo anterior crea una instancia de una clase interna anónima que es una subclase de la myclase abstracta. No es estrictamente equivalente a crear instancias de la clase abstracta en sí. 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 al instanciar una de sus subclases concretas.

Si el entrevistador acaba de decir "¡mal!" sin dar explicaciones, y dado este ejemplo, como un contraejemplo único, creo que no sabe de qué está hablando.


10
Estrictamente hablando, la superclase abstracta no se instancia. Se llama a su constructor para inicializar las variables de instancia.
Percepción el

44
Sí lo es: subclassInstance instanceof SuperClassdevolvería verdadero, por lo que el objeto es una instancia de la superclase, lo que significa que la superclase ha sido instanciada. Pero eso es solo un punto de mira semántico.
JB Nizet

55
Podría ser semántica de hecho. Java define la creación de instancias en términos de creación de objetos a través de la nueva palabra clave (que no puede hacer con una clase abstracta). Pero, por supuesto, la subclase concreta informará correctamente que es una instancia de cada miembro de su jerarquía principal.
Percepción el

11
El párrafo 4.12.6 de la JLS dice: "Se dice que un objeto es una instancia de su clase y de todas las superclases de su clase".
JB Nizet

85

= my() {};significa que hay una implementación anónima, no es simple ejecución de un objeto, que debería haber sido: = my(). Nunca se puede crear una instancia de una clase abstracta.


30

Solo observaciones que podrías hacer:

  1. ¿Por qué se polyextiende my? Esto es inútil ...
  2. ¿Cuál es el resultado de la compilación? Tres archivos: my.class, poly.classypoly$1.class
  3. Si podemos crear una instancia de una clase abstracta como esa, también podemos crear 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) e instanciarla.


¿Qué pasa con una instanciación de súper clase?

La superclase abstracta no es instanciada por nosotros sino por Java.

EDITAR: Pídele 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

+1 para la observación 3: por ejemplo, podemos hacer Serializable s = new Serializable() {};(que es bastante inútil) y si está etiquetado en su código daría class my$3(o cualquier clase y número adjunto)
Restablecer Mónica - notmaynard

18

Simplemente puede responder, en una sola línea.

No , nunca puedes instanciar Clase abstracta

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

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

Y, de acuerdo con la clase anónima, clase declarada e instanciada 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 POO.


17

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 todo se aclare :)"

Me gustaría 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 reacciona ante situaciones difíciles e inusuales. Al darte códigos incorrectos, probablemente quería ver si respondías. Para saber si tiene la confianza para enfrentarse a sus 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.


13

Las clases abstractas no pueden instanciarse, pero pueden subclasificarse. Ver este enlace

El mejor ejemplo es

Aunque la clase Calender tiene un método abstracto getInstance () , pero cuando dicesCalendar calc=Calendar.getInstance();

calc se refiere a la instancia de clase de la clase GregorianCalendar como "GregorianCalendar extiende Calendario "

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


11

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 abstracta si se implementa de forma incompleta; Dicha clase no se puede instanciar, pero se puede extender 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 nulo; o si la clase no tiene un constructor nular; o si la instancia 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 una referencia de objeto a un tipo abstracto.

Un ángulo diferente sobre esto - Teamplay 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 la gente" pueden ser más importantes aquí que las "habilidades técnicas". Si intenta probar su lado del argumento de manera competitiva y agresiva, entonces podría tener razón teóricamente, pero también podría hacer más daño al tener una pelea / "cara" dañina / crear un enemigo de lo que vale. Sea reconciliador y comprensivo para resolver sus diferencias. ¿Quién sabe, tal vez tienes "la 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 las personas mayores y realice un 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.


7

Es un hecho bien establecido que noabstract class puede ser instanciado 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$ndonde nestá el número de clase anónima)

Entonces, si descompila esta clase de Java, encontrará 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();
    }
}

4

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


4

Sobre 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 uno de los métodos abstractos del padre, entonces el niño también se vuelve abstracto
  • Las clases abstractas son inútiles sin clases infantiles

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


3

Puede decir:
no podemos crear una instancia de una clase abstracta, pero podemos usar newpalabras clave para crear una instancia de clase anónima simplemente agregando {}como cuerpo de implementación al final de la clase abstracta.


3

Extender una clase no significa que está 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, diría que no: no se puede crear una instancia de una clase abstracta. Pero, puedes extenderlo / heredarlo.

No se puede crear una instancia directa de una clase abstracta. Pero no significa que no pueda obtener una instancia de clase (no realmente una instancia de clase abstracta original) indirectamente. Quiero decir que no puedes crear una instancia de la clase abstracta original, pero puedes:

  1. Crea una clase vacía
  2. Heredarlo de la clase abstracta
  3. Instanciar la clase derivada

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.


2

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 (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, 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 declaran abstractas:

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 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 invocaría los métodos en él y obtendría la lógica, implementada en el descendiente concreto (y parcialmente en los métodos de la clase abstracta) 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.


2

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 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 del tipo Figura y Figura La variable de referencia Clase se usa para referirse a los objetos de Clase Rectángulo y Triángulo.


0

En realidad, no podemos crear un objeto de una clase abstracta directamente. Lo que creamos es una variable de referencia de una llamada abstracta. La variable de referencia se utiliza para referirse al objeto de la clase que hereda la clase abstracta, es decir, la subclase de la clase abstracta.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.