在我的一次面试中,有人问我:“我们是否可以实例化一个抽象类?”
我的回答是:“没有。我们不能”。但是,面试官告诉我:“错了,我们可以。”
我对此进行了一些争论。然后他让我自己在家试试。
abstract class my {
public void mymethod() {
System.out.print("Abstract");
}
}
class poly {
public static void main(String a[]) {
my m = new my() {};
m.mymethod();
}
}
在这里,我正在创建我的类的实例和调用抽象类的方法。有人能给我解释一下吗?我的面试真的错了吗?
你可以观察到:
为什么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
技术答案
抽象类不能被实例化——这是通过定义和设计实现的。
摘自JLS,第8章。类:
命名类可以声明为抽象类(§8.1.1.1),并且必须声明
抽象,如果没有完全实现;这样的类是不可能的
实例化,但可以通过子类扩展。
来自JSE 6 java文档的Classes.newInstance():
如果这个类表示一个抽象类,一个接口,一个数组
Class,一个基本类型,或void;或者类没有null构造函数;或者如果
实例化失败是由于其他原因。
当然,您可以实例化抽象类的具体子类(包括匿名子类),也可以对抽象类型的对象引用进行类型转换。
团队合作与社交智商:
在现实世界中,当我们处理复杂的技术和法律规范时,这种技术误解经常发生。
在这里,“人际交往能力”可能比“技术能力”更重要。如果你试图证明自己的观点,那么理论上你可能是正确的,但你也可能在战斗中造成更大的伤害/损害“面子”/制造敌人。以和解和理解的方式解决你们的分歧。谁知道呢——也许你“都是对的”,但对术语的含义略有不同??
谁知道呢——虽然不太可能,但也有可能面试官故意引入一个小冲突/误解,把你置于一个具有挑战性的环境中,看看你在情感和社交方面的表现如何。对同事要有礼貌和建设性,听从前辈的建议,在面试结束后通过电子邮件或电话解决任何挑战/误解。这表明你很积极,注重细节。
实例化一个抽象类是不可能的。
你真正能做的是,在一个抽象类中实现一些通用方法,而让其他方法未实现(将它们声明为抽象),并让具体的派生程序根据需要实现它们。
然后您可以创建一个工厂,该工厂返回这个抽象类的实例(实际上是他的实现者)。然后在工厂中决定选择哪个实现者。这被称为工厂设计模式:
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的接收者将调用他身上的方法并获得在具体的下降器中实现的逻辑(部分在抽象类方法中实现),而不知道他得到的具体实现是什么。这也称为控制反转或依赖注入。
不,我们不能创建抽象类的对象,而是创建抽象类的引用变量。引用变量用于引用派生类(抽象类的子类)的对象。
下面的例子说明了这个概念
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());
}
}
在这里,我们可以看到不能创建类型为Figure的对象,但可以创建类型为Figure的引用变量。这里我们创建了一个类型为Figure的引用变量,而Figure类引用变量用于引用Rectangle和Triangle类的对象。