Podemos instanciar uma classe abstrata?

573

Durante uma das minhas entrevistas, perguntaram-me "Se podemos instanciar uma aula abstrata?"

Minha resposta foi "Não. Não podemos". Mas, o entrevistador me disse: "Errado, nós podemos".

Eu argumentei um pouco sobre isso. Então ele me disse para tentar fazer isso sozinho em 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();
    }
}

Aqui, estou criando uma instância da minha classe e chamando o método da classe abstrata. Alguém por favor pode me explicar isso? Eu estava realmente errado durante a minha entrevista?

Ravi
fonte
2
Embora apenas ligeiramente relacionado, talvez seja possível instanciar uma classe abstrata em C ++: se você derivar uma classe não abstrata Bde uma abstrata A, durante a parte da construção da Binstância, que consiste Ano construtor da execução, o tipo de tempo de execução do objeto é realmente A. Apenas temporário no entanto.
Vlad
8
@jWeavers: O exemplo que ele deu está totalmente errado. Você deveria ter perguntado "então qual é a utilidade da classe abstrata" dele. Se você o está estendendo, por que está criando uma instância da classe estendida? É um completamente novo objeto, onde você acabar com nenhum dado ..
Suco de limão
3
Ou talvez o entrevistador queira verificar o quanto você está confiante em sua declaração em relação ao que ele propôs!
Sid
5
Ele mentiu para você. Você largou a bola quando falhou em apontar que não é o que esse código faz e explicar o que são subclasses anônimas. Ele provavelmente já sabia disso e queria ver se você sabia.
Candied_orange 4/04
2
Não foi um programa de perguntas, mas uma entrevista de emprego, certo? E daí que Java, ou C ++, permitisse instanciar classes abstratas? Você não faria isso, porque não é uma coisa inteligente a se fazer. No Objective-C, as classes abstratas são apenas abstratas por convenção, e instancia-las é um bug.
precisa saber é o seguinte

Respostas:

722

Aqui, eu estou criando instância da minha classe

Não, você não está criando a instância da sua classe abstrata aqui. Em vez disso, você está criando uma instância de uma subclasse anônima da sua classe abstrata. E então você está invocando o método em sua referência de classe abstrata apontando para objeto da subclasse .

Esse comportamento está claramente listado na JLS - Seção # 15.9.1 : -

Se a expressão de criação da instância de classe terminar em um corpo de classe, a classe que está sendo instanciada será uma classe anônima. Então:

  • Se T denota uma classe, uma subclasse direta anônima da classe nomeada por T é declarada. É um erro em tempo de compilação se a classe indicada por T for uma classe final.
  • Se T denota uma interface, uma subclasse direta anônima de Object que implementa a interface nomeada por T é declarada.
  • Nos dois casos, o corpo da subclasse é o ClassBody fornecido na expressão de criação da instância de classe.
  • A classe que está sendo instanciada é a subclasse anônima.

Ênfase minha.

Além disso, na JLS - Seção # 12.5 , você pode ler sobre o Processo de Criação de Objetos . Vou citar uma declaração a partir daqui:

Sempre que uma nova instância de classe é criada, o espaço de memória é alocado para ela, com espaço para todas as variáveis ​​de instância declaradas no tipo de classe e todas as variáveis ​​de instância declaradas em cada superclasse do tipo de classe, incluindo todas as variáveis ​​de instância que podem estar ocultas.

Pouco antes de uma referência ao objeto recém-criado ser retornada como resultado, o construtor indicado é processado para inicializar o novo objeto usando o seguinte procedimento:

Você pode ler sobre o procedimento completo no link que forneci.


Para ver praticamente que a classe que está sendo instanciada é uma subclasse anônima , basta compilar as duas classes. Suponha que você coloque essas classes em dois arquivos 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();
    }
}

Agora, compile seus arquivos de origem:

javac My.java Poly.java

Agora, no diretório em que você compilou o código-fonte, você verá os seguintes arquivos de classe:

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

Veja essa classe - Poly$1.class. É o arquivo de classe criado pelo compilador correspondente à subclasse anônima que você instanciaram usando o código abaixo:

new My() {};

Portanto, fica claro que há uma classe diferente sendo instanciada. Só que, essa classe recebe um nome somente após a compilação pelo compilador.

Em geral, todas as subclasses anônimas da sua classe serão nomeadas desta maneira:

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

Esses números indicam a ordem em que essas classes anônimas aparecem na classe anexa.

Rohit Jain
fonte
172
@coders. A resposta exata é: - Você não pode instanciar sua classe abstrata, mas pode instanciar uma subclasse concreta de sua classe abstrata.
Rohit Jain
16
Em uma linha, você pode dizer: - Você nunca pode instanciar uma classe abstrata. Esse é o objetivo de uma classe abstrata.
Rahul Tripathi
66
Parece que o entrevistador foi mais investido na resposta do que na sua ...
Neil T.
7
De acordo com outro comentário (com uma referência JLS ), "Diz-se que um objeto é uma instância de sua classe e de todas as superclasses de sua classe" - portanto, não estamos tecnicamente criando uma instância da classe abstrata aqui? ou seja, instanciar a classe abstrata?
Arshajii
6
@ARS Eu diria que há uma diferença entre ser um instance ofe instantiating. Você instancia apenas uma classe, enquanto esse objeto que você cria pode ser uma instância de várias classes devido à herança.
precisa
89

O exemplo acima instancia uma classe interna anônima, que é uma subclasse da myclasse abstrata. Não é estritamente equivalente a instanciar a própria classe abstrata. OTOH, toda instância de subclasse é uma instância de todas as suas superclasses e interfaces; portanto, a maioria das classes abstratas é realmente instanciada instanciando uma de suas subclasses concretas.

Se o entrevistador apenas disser "errado!" sem explicar, e deu este exemplo, como um contra-exemplo único, acho que ele não sabe do que está falando.

JB Nizet
fonte
10
A rigor , a superclasse abstrata não é instanciada. Seu construtor é chamado para inicializar variáveis ​​de instância.
Percepção
4
Sim, é: subclassInstance instanceof SuperClassretornaria true, portanto o objeto é uma instância da superclasse, o que significa que a superclasse foi instanciada. Mas isso é apenas nitpicking semântico.
JB Nizet
5
Poderia ser semântica de fato. Java define instanciação em termos de criação de objetos por meio da nova palavra-chave (o que você não pode fazer com uma classe abstrata). Mas é claro que a subclasse concreta relatará corretamente que é uma instância de todos os membros de sua hierarquia pai.
Percepção
11
o parágrafo 4.12.6 do JLS diz: "Diz-se que um objeto é uma instância de sua classe e de todas as superclasses de sua classe".
JB Nizet
85

= my() {};significa que há uma implementação anônimo, não é simples instanciação de um objeto, que deveria ter sido: = my(). Você nunca pode instanciar uma classe abstrata.

Ioan
fonte
30

Apenas observações que você pode fazer:

  1. Por que polyse estendemy ? Isso é inútil ...
  2. Qual é o resultado da compilação? Três arquivos: my.class, poly.classepoly$1.class
  3. Se podemos instanciar uma classe abstrata como essa, também podemos instanciar uma interface ... estranha ...


Podemos instanciar uma classe abstrata?

Não, não podemos. O que podemos fazer é criar uma classe anônima (esse é o terceiro arquivo) e instancia-la.


Que tal uma instancia super classe?

A superclasse abstrata não é instanciada por nós, mas por java.

EDIT: Peça a ele para testar isso

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

}

saída é:

false
class my$1
class my$2
ncenerar
fonte
+1 para observação 3: por exemplo, podemos fazer Serializable s = new Serializable() {};(o que é bastante inútil) e se marcado em seu código poderia dar class my$3(ou o que quer encerrar classe e número)
Reintegrar Monica - notmaynard
18

Você pode simplesmente responder, em apenas uma linha

Não , você nunca pode instalar a Abstract Class

Mas, o entrevistador ainda não concorda, então você pode dizer a ele / ela

tudo o que você pode fazer é criar uma classe anônima.

E, de acordo com a classe Anonymous, a classe declarada e instanciada no mesmo local / linha

Portanto, é possível que o entrevistador esteja interessado em verificar seu nível de confiança e o quanto você sabe sobre os OOPs.


fonte
17

A parte técnica foi bem abordada nas outras respostas e termina principalmente em:
"Ele está errado, ele não sabe nada, peça a ele para se juntar ao SO e esclarecer tudo isso :)"

Gostaria de abordar o fato (que foi mencionado em outras respostas) de que essa pode ser uma questão de estresse e é uma ferramenta importante para muitos entrevistadores saberem mais sobre você e como você reage a situações difíceis e incomuns. Ao fornecer códigos incorretos, ele provavelmente queria ver se você argumentou de volta. Saber se você tem confiança para enfrentar seus idosos em situações semelhantes a essa.

PS: Não sei por que, mas sinto que o entrevistador leu este post.

Mixcels
fonte
13

As classes abstratas não podem ser instanciadas, mas podem ser subclassificadas. Veja este link

O melhor exemplo é

Embora a classe Calender tenha um método abstrato getInstance () , mas quando você dizCalendar calc=Calendar.getInstance();

calc está se referindo à instância da classe GregorianCalendar como "GregorianCalendar estende o calendário "

Infact tipo interior annonymous permite criar uma subclasse não-nome da classe abstrata e uma instância desta.

Abhishek_Mishra
fonte
11

Resposta técnica

Classes abstratas não podem ser instanciadas - isto é por definição e design.

No JLS, capítulo 8. Classes:

Uma classe nomeada pode ser declarada abstrata (§8.1.1.1) e deve ser declarada abstrata se for implementada incompletamente; essa classe não pode ser instanciada, mas pode ser estendida por subclasses.

No JSE 6, o java doc para Classes.newInstance ():

InstantiationException - se essa classe representa uma classe abstrata, uma interface, uma classe de matriz, um tipo primitivo ou nulo; ou se a classe não tiver construtor nulo; ou se a instanciação falhar por algum outro motivo.

Obviamente, é possível instanciar uma subclasse concreta de uma classe abstrata (incluindo uma subclasse anônima) e também executar uma conversão de tipo de uma referência de objeto a um tipo abstrato.

Um ângulo diferente sobre isso - Teamplay e inteligência social:

Esse tipo de mal-entendido técnico acontece com frequência no mundo real quando lidamos com tecnologias complexas e especificações legalistas.

As "habilidades das pessoas" podem ser mais importantes aqui do que as "habilidades técnicas". Se competitiva e agressivamente tentar provar o seu lado do argumento, você pode estar teoricamente certo, mas também poderá causar mais dano ao ter uma "face" brutal / prejudicial / criar um inimigo do que vale a pena. Seja reconciliatório e compreensivo ao resolver suas diferenças. Quem sabe - talvez você esteja "certo", mas trabalhando com significados ligeiramente diferentes para termos?

Quem sabe - embora não seja provável, é possível que o entrevistador tenha introduzido deliberadamente um pequeno conflito / mal-entendido para colocá-lo em uma situação desafiadora e ver como você se comporta emocional e socialmente. Seja gentil e construtivo com os colegas, siga os conselhos dos idosos e siga após a entrevista para resolver qualquer desafio / mal-entendido - por e-mail ou telefonema. Mostra que você está motivado e detalhista.

Glen Best
fonte
7

É um fato bem estabelecido que nãoabstract class pode ser instanciado, pois todos responderam.

Quando o programa define classe anônima, o compilador realmente cria uma nova classe com nome diferente (tem o padrão EnclosedClassName$nem quen é o número da classe anônima)

Portanto, se você descompilar essa classe Java, encontrará o código abaixo:

minha classe

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

poly $ 1.class (a classe gerada da "classe 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();
    }
}
iTech
fonte
4

Não, você não pode instanciar uma classe abstrata. Instanciamos apenas uma classe anônima. Na classe abstrata, declaramos métodos abstratos e definimos apenas métodos concretos.

Vikas Agrahari
fonte
4

Sobre Classes Abstratas

  • Não é possível criar o objeto de uma classe abstrata
  • Pode criar variáveis ​​(pode se comportar como tipos de dados)
  • Se um filho não puder substituir pelo menos um método abstrato do pai, ele também se tornará abstrato
  • Classes abstratas são inúteis sem classes filho

O objetivo de uma classe abstrata é se comportar como uma base. Na hierarquia de herança, você verá classes abstratas no topo.

Priyankara
fonte
3

Você pode dizer:
não podemos instanciar uma classe abstrata, mas podemos usar a newpalavra-chave para criar uma instância de classe anônima apenas adicionando {}como corpo do implemento no final da classe abstrata.

Eddy
fonte
3

Estender uma classe não significa que você está instanciando a classe. Na verdade, no seu caso, você está criando uma instância da subclasse.

Tenho certeza de que as classes abstratas não permitem a iniciação. Então, eu diria que não: você não pode instanciar uma classe abstrata. Mas você pode estendê-lo / herdá-lo.

Você não pode instanciar diretamente uma classe abstrata. Mas isso não significa que você não pode obter uma instância da classe (e não uma instância da classe abstrata original) indiretamente. Quero dizer, você não pode instanciar a classe abstrata orginial, mas pode:

  1. Crie uma classe vazia
  2. Herdar da classe abstrata
  3. Instanciar a classe derviada

Portanto, você obtém acesso a todos os métodos e propriedades em uma classe abstrata por meio da instância da classe derivada.

Kas
fonte
2

É impossível instanciar uma classe abstrata. O que você realmente pode fazer, implementou alguns métodos comuns em uma classe abstrata e deixou outros não implementados (declarando-os abstratos) e deixou o descendente concreto implementá-los, dependendo de suas necessidades. Então você pode criar uma fábrica, que retorna uma instância dessa classe abstrata (na verdade, seu implementador). Na fábrica, você decide qual implementador escolher. Isso é conhecido como padrão de design 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
    }

O implementador concreto precisa implementar apenas os métodos declarados como abstratos, mas terá acesso à lógica implementada nessas classes em uma classe abstrata, que não é declarada abstrata:

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

Finalmente, a fábrica se parece com isso:

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

O receptor do AbstractGridManager chamaria os métodos e obteria a lógica, implementada no descendente concreto (e parcialmente nos métodos da classe abstrata) sem saber qual é a implementação concreta que ele obteve. Isso também é conhecido como inversão do controle ou injeção de dependência.

Picrochole
fonte
2

Não, não podemos criar o objeto da classe abstrata, mas criar a variável de referência da classe abstrata. A variável de referência é usada para se referir aos objetos de classes derivadas (subclasses da classe Abstract)

Aqui está o exemplo que ilustra esse conceito

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

Aqui vemos que não podemos criar o objeto do tipo Figura, mas podemos criar uma variável de referência do tipo Figura. Aqui, criamos uma variável de referência do tipo Figura e a variável de referência de classe de figura é usada para se referir aos objetos de retângulo e triângulo de classe.

Ketan G
fonte
0

Na verdade, não podemos criar diretamente um objeto de uma classe abstrata. O que criamos é uma variável de referência de uma chamada abstrata. A variável de referência é usada para Referir-se ao objeto da classe que herda a classe Abstract, ou seja, a subclasse da classe abstract.

Jency
fonte