在我的一次面试中,有人问我:“我们是否可以实例化一个抽象类?”

我的回答是:“没有。我们不能”。但是,面试官告诉我:“错了,我们可以。”

我对此进行了一些争论。然后他让我自己在家试试。

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

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

在这里,我正在创建我的类的实例和调用抽象类的方法。有人能给我解释一下吗?我的面试真的错了吗?


当前回答

关于抽象类

不能创建抽象类的对象 可以创建变量(可以像数据类型一样运行) 如果子对象不能重写父对象的至少一个抽象方法,那么子对象也将成为抽象对象 如果没有子类,抽象类是无用的

抽象类的目的是表现得像基类。在继承层次结构中,你会看到抽象类位于顶部。

其他回答

抽象类不能像每个人回答的那样被实例化,这是一个公认的事实。

当程序定义匿名类时,编译器实际上创建了一个具有不同名称的新类(具有EnclosedClassName$n模式,其中n是匿名类号)

所以如果你反编译这个Java类,你会发现如下代码:

my.class

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

Poly $1.class(匿名类的生成类)

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

抽象类不能被实例化,但可以被子类化。参见这个链接

最好的例子是

虽然Calendar类有一个抽象方法getInstance(),但是当你说Calendar calc=Calendar.getInstance();

calc引用类GregorianCalendar的类实例为“GregorianCalendar extends Calendar”

事实上,匿名内部类型允许您创建抽象类的一个无名称子类和它的一个实例。

你可以说:我们不能实例化一个抽象类,但我们可以使用new关键字创建一个匿名类实例,只需在抽象类的末尾添加{}作为实现体。

实例化一个抽象类是不可能的。 你真正能做的是,在一个抽象类中实现一些通用方法,而让其他方法未实现(将它们声明为抽象),并让具体的派生程序根据需要实现它们。 然后您可以创建一个工厂,该工厂返回这个抽象类的实例(实际上是他的实现者)。然后在工厂中决定选择哪个实现者。这被称为工厂设计模式:

   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
    }

具体实现者只需要实现声明为抽象的方法,但可以访问在抽象类中那些类中实现的逻辑,这些类不是声明为抽象的:

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

最后,工厂看起来是这样的:

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

AbstractGridManager的接收者将调用他身上的方法并获得在具体的下降器中实现的逻辑(部分在抽象类方法中实现),而不知道他得到的具体实现是什么。这也称为控制反转或依赖注入。

你可以观察到:

为什么poly扩展my?这没用…… 编译的结果是什么?三个文件:my.class, poly.class和poly$1.class 如果我们可以这样实例化一个抽象类,我们也可以实例化一个接口……奇怪的……

我们可以实例化一个抽象类吗?

不,我们不能。我们可以做的是,创建一个匿名类(这是第三个文件)并实例化它。

那么超类实例化呢?

抽象超类不是由我们实例化的,而是由java实例化的。

编辑:请他测试一下

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

}

输出是:

false
class my$1
class my$2