Interview: peut-on instancier une classe abstraite?

a demandé l'intervieweur - pouvons-nous instancier une classe abstraite? Je l'ai dit, Pas de. Il m'a dit de Mal, nous le pouvons.

j'ai argumenté un peu là-dessus. Puis il m'a dit d'essayer vous-même à votre domicile.

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 l'instance de ma classe et la méthode d'appel de la classe abstraite. Quelqu'un peut-il expliquer cela à moi? Ai-je vraiment eu tort pendant mon entretien?

532
demandé sur user2864740 2012-12-02 20:01:58

15 réponses

ici, je crée l'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'une sous-classe anonyme de votre classe abstraite. Et puis vous invoquez la méthode sur votre classe de résumé référence pointant vers objet de la sous-classe .

ce comportement est clairement indiqué dans JLS-Section # 15.9.1 : -

si l'expression de création d'instance de classe se termine dans un corps de classe, alors la classe instanciée est une classe anonyme. Puis:

  • Si T dénote une classe, alors une sous-classe directe anonyme de la classe nommée par T est déclarée. C'est une erreur de compilation si l' la classe indiquée par T est une classe finale.
  • Si T indique une interface, puis une sous-classe anonyme directe d'objet 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 corps de classe indiqué dans l'expression de création d'instance de classe.
  • La classe instanciée est anonyme sous-classe.

c'est moi qui souligne.

également, en JLS - Section # 12.5 , vous pouvez lire à propos du Object Creation Process . Je vais citer une déclaration de cela ici: -

Chaque fois qu'une nouvelle instance de classe est créée, l'espace mémoire est alloué pour lui avec la place pour toutes les variables d'instance déclarées dans la classe type et toutes les variables d'instance déclarées dans chaque superclasse de la type de classe, y compris toutes les variables d'instance qui peuvent être cachées.

juste avant qu'une référence à l'objet nouvellement créé soit retournée en tant que résultat, le constructeur indiqué est traité pour initialiser le nouveau objet selon la procédure suivante:

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


pour pratiquement voir que la classe instanciée est une sous-classe anonyme , il suffit de pour compiler vos 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.class  // Class file corresponding to anonymous subclass
Poly.class

voir que la classe Poly.class . C'est le fichier de classe créé par le compilateur correspondant à la sous-classe anonyme que vous avez instanciée en utilisant le code suivant:

new My() {};

Donc, il est clair qu'il existe une autre classe instanciée. C'est juste que, cette classe ne reçoit un nom qu'après compilation par le compilateur.

en général, toutes les sous-classes anonymes de votre classe seront nommées de cette façon:

Poly.class, Poly.class, Poly.class, ... so on

ceux les nombres indiquent l'ordre dans lequel ces classes anonymes apparaissent dans la classe qui les entoure.

675
répondu Rohit Jain 2013-08-26 10:51:59

l'exemple ci-dessus illustre une classe intérieure 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, de sorte que la plupart des classes abstraites sont effectivement instanciées en instanciant l'une de leurs sous-classes concrètes.

si l'intervieweur vient de dire " faux!"sans expliquer, et a donné cet exemple, comme un contre-exemple, je pense qu'il ne sait pas de quoi il parle.

89
répondu JB Nizet 2017-03-09 05:39:43

= my() {}; signifie qu'il y a 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.

83
répondu Ioan 2013-09-02 12:09:00

Juste observations que l'on pourrait faire:

  1. pourquoi poly étend my ? Ceci est inutile...
  2. Quel est le résultat de la compilation? Trois fichiers: my.class , poly.class et poly.class
  3. si nous pouvons instancier une classe abstraite comme celle-ci, nous pouvons instancier une interface aussi... étrange...



pouvons-nous instancier une classe abstraite?

non, on ne peut 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 us mais par java.

EDIT: demandez-lui de tester ce

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

}

sortie:

false
class my
class my
29
répondu ncenerar 2016-08-11 10:26:06

, Vous pouvez simplement les réponses, en une seule ligne

Non , vous ne pouvez jamais instance classe abstraite

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

tout ce que vous pouvez faire, c'est créer une classe anonyme.

, Et, selon la classe Anonyme, classe déclarée et instancier à la même lieu / ligne

il est donc possible que l'intervieweur soit intéressé à vérifier votre niveau de confiance et ce que vous savez au sujet de L'OOPs .

18
répondu 2012-12-07 04:14:18

la partie technique a été bien couverte dans les autres réponses, et elle se termine principalement en:

"Il a tort, il ne sait rien, demandez-lui de se joindre à nous et que tout soit clair:) "

je voudrais aborder le fait (qui a été mentionné dans d'autres réponses) qu'il pourrait s'agir d'un question de stress et est un outil important pour de nombreux intervieweurs pour en savoir plus sur vous et comment réagissez-vous à difficile et inhabituel situation. En vous donnant des codes incorrects, il probablement voulait voir si vous avez répondu. Pour savoir si vous avez la confiance nécessaire pour vous opposer à vos aînés dans des situations semblables.

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

16
répondu Mixcels 2015-04-07 05:20:32

les classes abstraites ne peuvent pas être instanciées, mais elles peuvent être subclassées. Voir Ce Lien

le meilleur exemple est

bien que Classe Calender a une méthode abstraite getInstance () , mais quand vous dites Calendar calc=Calendar.getInstance();

calc se réfère à l'instance de classe de GregorianCalendar classe comme "GregorianCalendar extends Calendar

Enfaite annonymous intérieure de type vous permet de créer un nom de sous-classe de la classe abstraite et une instance de cette.

13
répondu Abhishek_Mishra 2012-12-03 09:14:11

Réponse Technique

les classes Abstraites ne peuvent pas être instanciées - c'est par la définition et à la conception.

du JLS, Chapitre 8. Classes:

une classe désignée peut être déclarée abrégé (§8.1.1.1) et doit être déclarée abstraite si elle n'est que partiellement mis en œuvre; une telle classe ne peut pas être instancié, mais peut être prolongée par des sous-classes.

From JSE 6 java doc for Classes.newInstance ():

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

Vous pouvez, bien sûr, instancier un béton sous-classe d'une classe abstraite (y compris une sous-classe anonyme) et effectuent également une typographie d'un objet faisant référence à un type abstrait.

Un Angle Différent Sur Ceci-Teamplay & Intelligence Sociale:

ce genre de malentendu technique se produit fréquemment dans le monde réel lorsque nous traitons de technologies complexes et de spécifications juridiques.

"Compétences relationnelles", peut être plus important ici que les "Compétences Techniques". Si en essayant de prouver votre côté de l'argument de manière compétitive et agressive, alors vous pourriez avoir théoriquement raison, mais vous pourriez aussi faire plus de dégâts en ayant un combat / endommager "visage" / créer un ennemi qu'il ne vaut la peine. Soyez conciliant et compréhensif dans la résolution de vos différends. Qui sait - peut-être que vous avez "tous les deux raison" mais que vous travaillez sur des significations légèrement différentes pour les Termes??

, Qui sait, quoique peu probable, il est possible que l'intervieweur délibérément introduit un petit conflit / malentendu 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 continuez après l'entrevue pour résoudre tout problème ou malentendu, par courriel ou par téléphone. Montre que vous êtes motivé et avoir le souci du détail.

11
répondu Glen Best 2013-03-18 03:35:00

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

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

donc si vous décompilez cette classe Java, vous trouverez le code comme suit:

mon.classe

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

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

class poly 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
répondu iTech 2013-02-14 12:33:26

Non, vous ne pouvez pas instancier une classe abstraite.Nous n'instancions que des classes anonymes.Dans la classe abstraite nous déclarons des méthodes abstraites et définissons des méthodes concrètes seulement.

4
répondu vikas agrahari 2014-01-04 07:24:44

À Propos Des Classes Abstraites

  • ne peut pas créer l'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 outrepasser au moins une méthode abstraite du parent, alors l'enfant devient également abstrait
  • les classes Abstraites sont inutiles sans classes enfant

Le but d'un résumé la classe doit se comporter comme une base. Dans la hiérarchie de l'héritage, vous verrez des classes abstraites vers le haut.

4
répondu Priyankara 2017-03-09 06:01:48

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
répondu Eddy 2017-01-19 11:33:06

étendre une classe ne signifie pas que vous instanciez la classe. Effectivement, dans votre cas, vous créez une instance de la sous-classe.

je suis assez sûr que les classes abstraites ne permettent pas d'initier. Donc, je dirais non: on ne peut pas instancier une classe abstraite. Mais, vous pouvez l'étendre / en hériter.

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

  1. créer une classe vide
  2. hérite de classe abstraite
  3. Instanciate the dervied class

ainsi vous accédez à toutes les méthodes et propriétés d'une classe abstraite via l'instance de classe dérivée.

3
répondu Kas 2017-03-09 05:46:22

impossible d'instancier une classe abstraite. Ce que vous pouvez vraiment faire, c'est mettre en œuvre certaines méthodes communes dans une classe abstraite et laisser d'autres non mises en œuvre (les déclarer abstraites) et laisser les descendeurs concrets les mettre en œuvre en fonction de leurs besoins. Ensuite, vous pouvez faire une usine, qui renvoie une instance de cette classe abstraite (en fait son exécuteur). Dans l'usine, vous décidez alors, qui opérateur de choisir. C'est ce qu'on appelle un dessin 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'exécutant concret n'a besoin que de mettre en œuvre les méthodes déclarées abstraites, mais aura accès à la logique mise en œuvre 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;
    }
}

puis finalement l'usine ressemble à quelque chose comme 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 récepteur D'AbstractGridManager appellerait les méthodes sur lui et obtiendrait la logique, mise en œuvre dans le descender concret (et en partie dans les méthodes de classe abstraites) sans savoir quelle est la mise en œuvre concrète qu'il a obtenu. Ceci est également connu sous le nom d'inversion de contrôle ou d'injection de dépendance.

2
répondu Picrochole 2017-03-09 06:46:33

Non, nous ne pouvons pas créer l'objet de la 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 se référer aux objets des classes dérivées (sous-classes de 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()); 
    } 
}

ici nous voyons 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 référence variable de type Figure et classe de Figure la variable de référence est utilisée pour se référer aux objets de la classe Rectangle et Triangle.

1
répondu Ketan G 2017-03-09 08:40:02