Intervista: possiamo creare un’istanza di class astratta?

L’intervistatore ha chiesto: possiamo creare un’istanza di una class astratta? Ho detto, No. Mi ha detto – Sbagliato, possiamo.

Ho discusso un po ‘su questo. Poi mi ha detto di provare questo te stesso a casa tua.

abstract class my { public void mymethod() { System.out.print("Abstract"); } } class poly { public static void main(String a[]) { my m = new my() {}; m.mymethod(); } } 

Qui sto creando l’istanza della mia class e il metodo di chiamata della class astratta. Qualcuno può spiegarmi questo per favore? Ho sbagliato davvero durante la mia intervista?

Ecco, sto creando l’istanza della mia class

No, non stai creando l’istanza della tua class astratta qui. Piuttosto, stai creando un’istanza di una sottoclass anonima della tua class astratta. E quindi stai invocando il metodo sul riferimento della class astratta che punta all’object sottoclass .

Questo comportamento è chiaramente elencato in JLS – Sezione # 15.9.1 : –

Se l’espressione di creazione dell’istanza di class termina in un corpo di una class, la class che viene istanziata è una class anonima. Poi:

  • Se T denota una class, viene dichiarata una sottoclass diretta anonima della class chiamata da T. È un errore in fase di compilazione se la class indicata da T è una class finale.
  • Se T denota un’interfaccia, viene dichiarata una sottoclass diretta anonima di Object che implementa l’interfaccia chiamata da T.
  • In entrambi i casi, il corpo della sottoclass è ClassBody indicato nell’espressione di creazione dell’istanza di class.
  • La class istanziata è la sottoclass anonima.

Enfasi mia.

Inoltre, in JLS – Sezione # 12.5 , puoi leggere il processo di creazione degli oggetti . Citerò una dichiarazione da qui:

Ogni volta che viene creata una nuova istanza di class, viene allocata per essa spazio di memoria con tutte le variabili di istanza dichiarate nel tipo di class e tutte le variabili di istanza dichiarate in ogni superclass del tipo di class, comprese tutte le variabili di istanza che possono essere nascoste.

Appena prima viene restituito un riferimento all’object appena creato, il costruttore indicato viene elaborato per inizializzare il nuovo object usando la seguente procedura:

Puoi leggere la procedura completa sul link che ho fornito.


Per vedere praticamente che la class istanziata è una Sottoclass anonima , devi solo compilare entrambe le classi. Supponi di mettere quelle classi in due file diversi:

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

Ora, compila entrambi i tuoi file sorgente:

 javac My.java Poly.java 

Ora nella directory in cui hai compilato il codice sorgente, vedrai i seguenti file di class:

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

Vedi quella lezione – Poly$1.class . È il file di class creato dal compilatore corrispondente alla sottoclass anonima istanziata utilizzando il codice seguente:

 new My() {}; 

Quindi, è chiaro che è stata istanziata una class diversa. È solo che, a questa class viene assegnato un nome solo dopo la compilazione da parte del compilatore.

In generale, tutte le sottoclassi anonime della class verranno denominate in questo modo:

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

Questi numeri indicano l’ordine in cui tali classi anonime compaiono nella class che le racchiude.

Quanto sopra istanzia una class interiore anonima che è una sottoclass della my class astratta. Non è strettamente equivalente all’istanziazione della class astratta stessa. OTOH, ogni istanza di sottoclass è un’istanza di tutte le sue super classi e interfacce, quindi molte classi astratte sono effettivamente istanziate istanziando una delle loro sottoclassi concrete.

Se l’intervistatore ha appena detto “sbagliato!” senza spiegare, e dato questo esempio, come un controesempio unico, penso che non sappia di cosa sta parlando, però.

= my() {}; significa che esiste un’implementazione anonima, non una semplice istanziazione di un object, che avrebbe dovuto essere: = my() . Non puoi mai istanziare una class astratta.

Solo osservazioni che potresti fare:

  1. Perché poly estende la my ? Questo è inutile …
  2. Qual è il risultato della compilation? Tre file: my.class , poly.class e poly$1.class
  3. Se siamo in grado di creare un’istanza di una class astratta come questa, possiamo anche istanziare un’interfaccia … strano …

Possiamo creare un’istanza di una class astratta?

No, non possiamo. Quello che possiamo fare è creare una class anonima (che è il terzo file) e istanziarla.

Che dire di una istanziazione di super class?

La super class astratta non è istanziata da noi ma da java.

EDIT: chiedigli di testare questo

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

l’output è:

 false class my$1 class my$2 

Puoi semplicemente risposte, in una sola riga

No , non puoi mai istanziare una class astratta

Ma l’intervistatore non è ancora d’accordo, quindi puoi dirglielo

tutto ciò che puoi fare è creare una class anonima.

E, secondo la class di Anonymous, class dichiarata e istanziata nello stesso luogo / linea

Quindi, potrebbe essere ansible che l’intervistatore sarebbe interessato a verificare il tuo livello di confidenza e quanto sai sulle OOP.

La parte tecnica è stata ben trattata nelle altre risposte e si conclude principalmente in:
“Ha torto, non sa niente, gli chiede di unirsi a SO e di chiarire tutto :)”

Vorrei affrontare il fatto (che è stato menzionato in altre risposte) che questa potrebbe essere una domanda di stress ed è uno strumento importante per molti intervistatori per sapere di più su di te e come reagisci a situazioni difficili e insolite. Dandogli codici errati, probabilmente voleva vedere se avevi litigato. Per sapere se hai la sicurezza di opporsi ai tuoi anziani in situazioni simili a questo.

PS: Non so perché, ma ho la sensazione che l’intervistatore abbia letto questo post.

Le classi astratte non possono essere istanziate, ma possono essere sottoclassate. Vedi questo link

Il miglior esempio è

Sebbene la class Calender abbia un metodo astratto getInstance () , ma quando si dice Calendar calc=Calendar.getInstance();

calc si riferisce all’istanza di class della class GregorianCalendar come “GregorianCalendar estende il calendario

Infatti, il tipo interno anonimo consente di creare una sottoclass senza nome della class astratta e un’istanza di questo.

Risposta tecnica

Le classi astratte non possono essere istanziate – questo è per definizione e design.

Dal JLS, capitolo 8. Classi:

Una class nominata può essere dichiarata astratta (§8.1.1.1) e deve essere dichiarata astratta se è implementata in modo incompleto; tale class non può essere istanziata, ma può essere estesa per sottoclassi.

Da JSE 6 java doc per Classes.newInstance ():

InstantiationException – se questa class rappresenta una class astratta, un’interfaccia, una class array, un tipo primitivo o vuoto; o se la class non ha costruttori nullari; o se l’istanziazione non riesce per qualche altra ragione.

È ansible, naturalmente, creare un’istanza di una sottoclass concreta di una class astratta (inclusa una sottoclass anonima) e anche eseguire un typecast di un riferimento a un tipo astratto.

Un angolo diverso su questo: gioco di squadra e intelligenza sociale:

Questo tipo di fraintendimenti tecnici si verificano spesso nel mondo reale quando ci occupiamo di tecnologie complesse e specifiche legali.

“Abilità della gente” può essere più importante qui di “Abilità tecniche”. Se si cerca in modo competitivo e aggressivo di dimostrare il proprio punto di vista, allora si potrebbe essere teoricamente corretti, ma si potrebbe anche fare più danno nell’avere un “volto” di combattimento / danno / creare un nemico di quanto valga. Sii riconciliato e comprensivo nel risolvere le tue differenze. Chissà, forse hai “entrambi ragione” ma stai lavorando su significati leggermente diversi per i termini ??

Chi lo sa, anche se non è probabile, è ansible che l’intervistatore abbia introdotto deliberatamente un piccolo conflitto / incomprensione per metterti in una situazione difficile e vedere come ti comporti emotivamente e socialmente. Sii gentile e costruttivo con i colleghi, segui i consigli degli anziani e segui dopo l’intervista per risolvere qualsiasi sfida / incomprensione, tramite e-mail o telefonata. Mostra che sei motivato e attento ai dettagli.

È un fatto consolidato che la abstract class non può essere istanziata come tutti hanno risposto.

Quando il programma definisce la class anonima, il compilatore crea effettivamente una nuova class con un nome diverso (ha il modello EnclosedClassName$n dove n è il numero della class anonima)

Quindi se decompilate questa class Java troverete il codice come di seguito:

la mia class

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

poly $ 1.class (la class generata della “class anonima”)

 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, non è ansible istanziare una class astratta. Istituiamo solo classi anonime. Nella class astratta dichiariamo metodi astratti e definiamo solo metodi concreti.

Informazioni sulle classi astratte

  • Imansible creare l’object di una class astratta
  • Può creare variabili (può comportarsi come tipi di dati)
  • Se un bambino non può scavalcare almeno un metodo astratto del genitore, anche il bambino diventa astratto
  • Le classi astratte sono inutili senza classi di bambini

Lo scopo di una class astratta è comportarsi come una base. Nella gerarchia dell’eredità vedrai classi astratte verso l’alto.

Si può dire:
non possiamo creare un’istanza di una class astratta, ma possiamo usare la new parola chiave per creare un’istanza di class anonima aggiungendo semplicemente {} come corpo dell’attrezzo alla fine della class astratta.

Estendere una class non significa che stai istanziando la class. In realtà, nel tuo caso stai creando un’istanza della sottoclass.

Sono abbastanza sicuro che le classi astratte non consentono l’avvio. Quindi, direi di no: non è ansible creare un’istanza di una class astratta. Ma puoi estenderlo / ereditarlo.

Non è ansible creare direttamente un’istanza di una class astratta. Ma ciò non significa che non sia ansible ottenere un’istanza di class (non necessariamente un’istanza della class astratta originale) indirettamente. Voglio dire che non puoi istanziare la class astratta originale, ma puoi:

  1. Crea una class vuota
  2. Eredita dalla class astratta
  3. Istanzia la class dei dervisci

In questo modo si ottiene l’accesso a tutti i metodi e le proprietà in una class astratta tramite l’istanza della class derivata.

È imansible creare un’istanza di una class astratta. Quello che puoi veramente fare, ha implementato alcuni metodi comuni in una class astratta e lasciare che altri non siano implementati (dichiarandoli astratti) e lasciare che il discensore concreto li implementa a seconda delle loro esigenze. Quindi puoi creare una factory, che restituisce un’istanza di questa class astratta (in realtà il suo implementatore). Nella fabbrica decidi, quale implementatore scegliere. Questo è noto come modello di progettazione di fabbrica:

  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’implementatore concreto deve solo implementare i metodi dichiarati come astratti, ma avrà accesso alla logica implementata in quelle classi in una class astratta, che non sono dichiarate astratte:

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

Poi finalmente la fabbrica assomiglia a qualcosa del genere:

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

Il ricevitore di AbstractGridManager chiamerebbe i metodi su di lui e otterrebbe la logica, implementata nel discensore concreto (e parzialmente nei metodi astratti di class) senza sapere quale sia l’implementazione concreta che ha ottenuto. Questo è anche noto come inversione di iniezione di controllo o dipendenza.

No, non possiamo creare l’object della class astratta, ma creare la variabile di riferimento della class astratta. La variabile di riferimento viene utilizzata per fare riferimento agli oggetti delle classi derivate (Sottoclassi di class Abstract)

Ecco l’esempio che illustra questo concetto

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

Qui vediamo che non possiamo creare l’object di tipo Figura ma possiamo creare una variabile di riferimento di tipo Figura. Qui abbiamo creato una variabile di riferimento di tipo Figura e Figura La variabile di riferimento della class viene utilizzata per fare riferimento agli oggetti di Class Rectangle e Triangle.