web-dev-qa-db-fra.com

Peut-on instancier une classe abstraite?

Au cours d'une de mes interviews, on m'a demandé "Si nous pouvons instancier un cours abstrait?"

Ma réponse a été "Non, nous ne pouvons pas". Mais l'intervieweur m'a dit "Faux, on peut."

J'ai discuté un peu à ce sujet. Puis il m'a dit d'essayer moi-même à la maison.

abstract class my {
    public void mymethod() {
        System.out.print("Abstract");
    }
}

class poly {
    public static void main(String a[]) {
        my m = new my() {};
        m.mymethod();
    }
}

Ici, je crée une instance de ma classe et une méthode d'appel de classe abstraite. Quelqu'un peut-il m'expliquer s'il vous plaît? Avais-je vraiment tort pendant mon entretien?

556
Ravi

Ici, je crée une instance de ma classe

Non, vous ne créez pas l'instance de votre classe abstraite ici. Vous créez plutôt une instance d'un sous-classe anonyme de votre classe abstraite. Et ensuite, vous appelez la méthode sur votre classe abstraite référence pointant vers objet de sous-classe .

Ce comportement est clairement répertorié dans JLS - Section # 15.9.1 : -

Si l'expression de création d'instance de classe se termine par un corps de classe, la classe en cours d'instanciation est une classe anonyme. Ensuite:

  • Si T désigne une classe, une sous-classe directe anonyme de la classe nommée par T est déclarée. C'est une erreur de compilation si la classe notée T est une classe finale.
  • Si T désigne une interface, une sous-classe directe anonyme d'Object qui implémente l'interface nommée par T est déclarée.
  • Dans les deux cas, le corps de la sous-classe est le ClassBody donné dans l'expression de création d'instance de classe.
  • La classe en cours d'instanciation est la sous-classe anonyme.

L'accent est à moi.

En outre, dans JLS - Section # 12.5 , vous pouvez en savoir plus sur le processus de création d’objet . Je vais citer une déclaration de cela ici: -

Chaque fois qu'une nouvelle instance de classe est créée, de la mémoire lui est allouée, ainsi que toutes les variables d'instance déclarées dans le type de classe et toutes les variables d'instance déclarées dans chaque superclasse du type de classe, y compris toutes les variables d'instance pouvant être masquées.

Juste avant qu'une référence à l'objet nouvellement créé soit renvoyée en tant que résultat, le constructeur indiqué est traité pour initialiser le nouvel objet à l'aide de la procédure suivante:

Vous pouvez lire sur la procédure complète sur le lien que j'ai fourni.


Pour voir pratiquement que la classe en cours d'instanciation est un Anonymous SubClass , il vous suffit de compiler vos deux classes. Supposons que vous mettiez ces classes dans deux fichiers différents:

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();
    }
}

Maintenant, compilez vos deux fichiers source:

javac My.Java Poly.Java

Maintenant, dans le répertoire où vous avez compilé le code source, vous verrez les fichiers de classe suivants:

My.class
Poly$1.class  // Class file corresponding to anonymous subclass
Poly.class

Voir cette classe - Poly$1.class. C'est le fichier de classe créé par le compilateur correspondant à la sous-classe anonyme que vous avez instanciée à l'aide du code ci-dessous:

new My() {};

Donc, il est clair qu’une classe différente est instanciée. C'est juste que cette classe reçoit un nom seulement après la compilation par le compilateur.

En général, toutes les sous-classes anonymes de votre classe seront nommées de cette manière:

Poly$1.class, Poly$2.class, Poly$3.class, ... so on

Ces nombres indiquent l'ordre dans lequel ces classes anonymes apparaissent dans la classe englobante.

701
Rohit Jain

Ce qui précède instancie une classe interne anonyme qui est une sous-classe de la classe abstraite my. Ce n'est pas strictement équivalent à instancier la classe abstraite elle-même. OTOH, chaque instance de sous-classe est une instance de toutes ses super-classes et interfaces. Par conséquent, la plupart des classes abstraites sont instanciées en instanciant l'une de leurs sous-classes concrètes.

Si l'intervieweur a juste dit "faux!" sans expliquer, et a donné cet exemple, comme contre-exemple unique, je pense qu'il ne sait pas de quoi il parle, cependant.

89
JB Nizet

= my() {}; signifie qu'il existe une implémentation anonyme, et non une simple instanciation d'un objet, qui aurait dû être: = my(). Vous ne pouvez jamais instancier une classe abstraite.

84
Ioan

Juste observations que vous pourriez faire:

  1. Pourquoi poly étend my? C'est inutile ...
  2. Quel est le résultat de la compilation? Trois fichiers: my.class, poly.class et poly$1.class
  3. Si nous pouvons instancier une classe abstraite comme ça, nous pouvons aussi instancier une interface ... bizarre ...


Peut-on instancier une classe abstraite?

Non, nous ne pouvons pas. Ce que nous pouvons faire, c'est créer une classe anonyme (c'est le troisième fichier) et l'instancier.


Qu'en est-il d'une instanciation de super classe?

La super classe abstraite n'est pas instanciée par s mais par Java.

EDIT: Demandez-lui de tester cela

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 sortie est:

false
class my$1
class my$2
30
ncenerar

Vous pouvez simplement répondre, en une seule ligne

Non, vous ne pouvez jamais créer une classe abstraite

Mais l'intervieweur n'est toujours pas d'accord, alors vous pouvez lui dire

tout ce que vous pouvez faire est de créer une classe anonyme.

Et, selon la classe Anonymous, classe déclarée et instanciée au même endroit/ligne

Il est donc possible que l’intervieweur veuille vérifier votre niveau de confiance et vos connaissances sur les POO.

18
user918477

La partie technique a été bien couverte dans les autres réponses et se termine principalement par:
"Il a tort, il ne sait rien, demandez-lui de rejoindre SO et que tout soit effacé :)"

Je voudrais aborder le fait (qui a été mentionné dans d'autres réponses) qu'il pourrait s'agir d'une question de stress et constitue un outil important pour de nombreux interviewers afin d'en savoir plus sur vous et comment réagissez-vous situations difficiles et inhabituelles. En vous donnant des codes incorrects, il voulait probablement voir si vous vous disputiez. Pour savoir si vous avez la confiance nécessaire pour vous opposer à vos aînés dans des situations similaires.

P.S: Je ne sais pas pourquoi mais j'ai le sentiment que l'intervieweur a lu ce post.

16
Mixcels

Les classes abstraites ne peuvent pas être instanciées, mais elles peuvent être sous-classées. Voir ce lien

Le meilleur exemple est

Bien que la classe Calender ait une méthode abstraite getInstance () , mais lorsque vous dites Calendar calc=Calendar.getInstance();

calc fait référence à l'instance de classe de la classe GregorianCalendar en tant que "GregorianCalendar extend Calendar "

Enfait de type interne annymous vous permet de créer une sous-classe sans nom de la classe abstraite et une instance de cela.

13
Abhishek_Mishra

Réponse technique

Les classes abstraites ne peuvent pas être instanciées - ceci est par définition et par conception.

Du JLS, Chapitre 8. Classes:

Une classe nommée peut être déclarée abstraite (§8.1.1.1) et doit être déclarée abstraite si sa mise en œuvre est incomplète; une telle classe ne peut pas être instanciée, mais peut être étendue par des sous-classes.

De JSE 6 Java doc pour Classes.newInstance ():

InstantiationException - si cette classe représente une classe abstraite, une interface, une classe de tableau, un type primitif ou void; ou si la classe n'a pas de constructeur de nullaire; ou si l'instanciation échoue pour une autre raison.

Vous pouvez bien sûr instancier une sous-classe concrète d'une classe abstraite (y compris une sous-classe anonyme) et également effectuer un transtypage d'une référence d'objet à un type abstrait.

n angle différent sur ceci - Teamplay & Social Intelligence:

Ce genre de malentendu technique se produit fréquemment dans le monde réel lorsque nous traitons avec des technologies complexes et des spécifications légalistes.

Les "compétences interpersonnelles" peuvent être plus importantes ici que les "compétences techniques". Si vous tentiez de prouver votre argumentation de manière compétitive et agressive, alors vous pourriez théoriquement avoir raison, mais vous pourriez également faire plus de dégâts en ayant un "visage" de combat/de dégâts qui créerait un ennemi qu'il ne valait. Soyez conciliant et compréhensif dans la résolution de vos différends. Qui sait - peut-être que vous avez raison, mais que vous employez des termes légèrement différents ??

Qui sait - bien que ce ne soit probablement pas le cas, l'intervieweur a délibérément introduit un petit conflit/incompréhension pour vous mettre dans une situation difficile et voir comment vous vous comportez émotionnellement et socialement. Soyez courtois et constructif avec vos collègues, suivez les conseils des aînés et faites le suivi après l'entrevue pour résoudre tout problème/incompréhension - par courrier électronique ou par téléphone. Montre que vous êtes motivé et soucieux des détails.

11
Glen Best

C'est un fait bien établi que abstract class peut pas être instancié comme tout le monde a répondu.

Lorsque le programme définit une classe anonyme, le compilateur crée en fait une nouvelle classe avec un nom différent (a le modèle EnclosedClassName$nn est le numéro de classe anonyme)

Donc, si vous décompilez cette classe Java, vous trouverez le code ci-dessous:

ma classe

abstract class my { 
    public void mymethod() 
    { 
        System.out.print("Abstract"); 
    }
} 

poly $ 1.class (la classe générée de la "classe anonyme")

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();
    }
}
7
iTech

À propos des classes abstraites

  • Impossible de créer un objet d'une classe abstraite
  • Peut créer des variables (peut se comporter comme des types de données)
  • Si un enfant ne peut pas remplacer au moins une méthode abstraite du parent, il devient aussi abstrait.
  • Les classes abstraites sont inutiles sans les classes enfants

Le but d'une classe abstraite est de se comporter comme une base. Dans la hiérarchie d'héritage, vous verrez les classes abstraites vers le haut.

4
Priyankara

Non, vous ne pouvez pas instancier une classe abstraite.Nous n'instancions qu'une classe anonyme.En classe abstraite, nous déclarons des méthodes abstraites et définissons uniquement des méthodes concrètes.

4
vikas agrahari

Vous pouvez dire:
nous ne pouvons pas instancier une classe abstraite, mais nous pouvons utiliser le mot clé new pour créer une instance de classe anonyme en ajoutant simplement {} comme corps d'implémentation à la fin de la classe abstraite.

3
Eddy

L'extension d'une classe ne signifie pas que vous instanciez la classe. En fait, dans votre cas, vous créez une instance de la sous-classe.

Je suis à peu près sûr que les classes abstraites ne permettent pas d'initier. Donc, je dirais non: vous ne pouvez pas instancier une classe abstraite. Mais, vous pouvez l'étendre/l'hériter.

Vous ne pouvez pas instancier directement une classe abstraite. Mais cela ne signifie pas que vous ne pouvez pas obtenir indirectement une instance de classe (et non une instance de classe abstraite originale). Je veux dire que vous ne pouvez pas instancier la classe abstraite d'origine, mais vous pouvez:

  1. Créer une classe vide
  2. Hériter de la classe abstraite
  3. Instancier la classe déréglée

Vous avez donc accès à toutes les méthodes et propriétés d'une classe abstraite via l'instance de classe dérivée.

3
Kas

Non, nous ne pouvons pas créer l'objet de classe abstraite, mais créer la variable de référence de la classe abstraite. La variable de référence est utilisée pour faire référence aux objets des classes dérivées (sous-classes de la classe abstraite)

Voici l'exemple qui illustre ce concept

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()); 
    } 
}

Nous voyons ici que nous ne pouvons pas créer l'objet de type Figure, mais nous pouvons créer une variable de référence de type Figure. Ici, nous avons créé une variable de référence de type Figure et Figure La variable de référence de classe est utilisée pour faire référence aux objets de classe Rectangle et Triangle.

2
Ketan G

Il est impossible d'instancier une classe abstraite. Ce que vous pouvez vraiment faire, a mis en œuvre des méthodes communes dans une classe abstraite et laissé les autres non implémentées (en les déclarant abstraites) et laissé le descender concret les implémenter en fonction de leurs besoins. Vous pouvez ensuite créer une fabrique, qui renvoie une instance de cette classe abstraite (en réalité son implémenteur). Dans l’usine, vous décidez ensuite quel installateur choisir. Ceci est connu comme un modèle de conception d'usine:

   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
    }

L'implémenteur concret n'a besoin que d'implémenter les méthodes déclarées comme abstraites, mais aura accès à la logique implémentée dans ces classes dans une classe abstraite, qui ne sont pas déclarées abstraites:

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;
    }
}

Enfin, l’usine ressemble à ceci:

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;
    }
}

Le destinataire de AbstractGridManager appelle les méthodes sur lui et obtient la logique, implémentée dans le descender concret (et partiellement dans les méthodes de classe abstraites) sans savoir quelle est l'implémentation concrète qu'il a obtenue. Ceci est également connu sous le nom d'inversion de contrôle ou d'injection de dépendance.

2
Picrochole