访谈:我们可以实例化抽象类吗?

Rav*_*avi 561 java oop class object abstract

采访者问:我们可以实例化一个抽象类吗?我说,不,他告诉我 - 错,我们可以.

我对此有点争论.然后他告诉我自己在家里试试.

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

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

在这里,我正在创建我的类的实例并调用抽象类的方法.有人可以向我解释一下吗?在我的采访中我真的错了吗?

Roh*_*ain 707

在这里,我正在创建我的班级实例

不,您不是在这里创建抽象类的实例.而是在创建抽象类的匿名子类的实例.然后,您在指向子类对象的抽象类引用上调用该方法.

JLS中明确列出了此行为- 第15.9.1节: -

如果类实例创建表达式在类主体中结束,则实例化的类是匿名类.然后:

  • 如果T表示一个类,则声明由T命名的类的匿名直接子类.如果由T表示的类是最终类,则是编译时错误.
  • 如果T表示接口,则声明实现由T命名的接口的Object的匿名直接子类.
  • 在任何一种情况下,子类的主体都是类实例创建表达式中给出的ClassBody.
  • 被实例化的类是匿名子类.

强调我的.

此外,在JLS - Section#12.5中,您可以阅读有关对象创建过程的信息.我在这里引用一句话: -

每当创建一个新的类实例时,就会为它分配内存空间,为类类型中声明的所有实例变量提供空间,并在类类型的每个超类中声明所有实例变量,包括可能隐藏的所有实例变量.

在作为结果返回对新创建的对象的引用之前,处理指示的构造函数以使用以下过程初始化新对象:

您可以在我提供的链接上阅读有关完整程序的信息.


实际上,要实例化的类是Anonymous SubClass,您只需要编译两个类.假设您将这些类放在两个不同的文件中:

My.java:

abstract class My {
    public void myMethod() {
        System.out.print("Abstract");
    }
}
Run Code Online (Sandbox Code Playgroud)

Poly.java:

class Poly extends My {
    public static void main(String a[]) {
        My m = new My() {};
        m.myMethod();
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,编译两个源文件:

javac My.java Poly.java
Run Code Online (Sandbox Code Playgroud)

现在,在编译源代码的目录中,您将看到以下类文件:

My.class
Poly$1.class  // Class file corresponding to anonymous subclass
Poly.class
Run Code Online (Sandbox Code Playgroud)

看那个班 - Poly$1.class.它是由编译器创建的类文件,对应于您使用以下代码实例化的匿名子类:

new My() {};
Run Code Online (Sandbox Code Playgroud)

因此,很明显有一个不同的类被实例化.就是这样,只有在编译器编译之后,该类才会被赋予名称.

通常,类中的所有匿名子类都将以这种方式命名:

Poly$1.class, Poly$2.class, Poly$3.class, ... so on
Run Code Online (Sandbox Code Playgroud)

这些数字表示这些匿名类在封闭类中出现的顺序.

  • @coders.确切的答案是: - 您不能实例化您的抽象类,但是您可以实例化抽象类的具体子类. (166认同)
  • 这听起来像面试官在他的答案中投入的比他在你的答案中更多...... (65认同)
  • 因此,简单的"否"也是正确的答案. (55认同)
  • 在一行中你可以说: - 你永远不能实例化一个抽象类.这是抽象类的目的. (16认同)
  • 根据[另一条评论](http://stackoverflow.com/questions/13670991/interview-can-we-instantiate-abstract-class#comment18765570_13671010)([JLS参考](http://docs.oracle.com) /javase/specs/jls/se7/html/jls-4.html#jls-4.12.6)),"一个对象被认为是它的类及其类的所有超类的实例" - 因此,不是'我们实际上在技术上创建了抽象类的实例吗?即实例化抽象类? (7认同)
  • @ARS我会说,作为`实例'和`实例化'之间存在差异.您只实例化一个类,而您创建的对象由于继承而可以是多个类的实例. (6认同)
  • @RohitJain:你为什么"延伸我的?"?它可能不需要你的答案. (4认同)

JB *_*zet 88

上面实例化了一个匿名内部类,它是my抽象类的子类.它并不完全等同于实例化抽象类本身.OTOH,每个子类实例都是其所有超类和接口的实例,因此大多数抽象类确实通过实例化其中一个具体子类来实例化.

如果面试官只是说"错!" 虽然没有解释,并且举了这个例子,作为一个独特的反例,我认为他不知道他在说什么.

  • [JLS第4.12.6段](http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.12.6)说:"一个对象据说是是它的类的实例和它的类的所有超类." (11认同)
  • ***严格地说,抽象超类没有实例化.它的构造函数被调用来初始化实例变量. (10认同)
  • 确实可能是语义.Java通过***new***关键字创建对象来定义*instantiation*(你不能用抽象类来实现).但是,具体的子类当然会正确地报告它的父层次结构的每个成员的实例. (5认同)
  • 是的:`subclassInstance instanceof SuperClass`将返回true,因此该对象是超类的实例,这意味着超类已经实例化.但那只是语义上的挑剔. (4认同)

Ioa*_*oan 85

= my() {};意味着有一个匿名实现,而不是对象的简单实例化,它应该是:= my().您永远不能实例化抽象类.


nce*_*rar 30

只是你可以做出的观察:

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


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

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


超类实例化怎么样?

抽象超类不是由我们实例化的,而是由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());

}
Run Code Online (Sandbox Code Playgroud)

输出是:

false
class my$1
class my$2
Run Code Online (Sandbox Code Playgroud)


小智 18

您只需一行即可轻松回答问题

,你永远不能实例抽象类

但是,面试官仍然不同意,那么你可以告诉他/她

你所能做的就是,你可以创建一个匿名类.

并且,根据Anonymous类,类声明并在同一位置/行实例化

因此,面试官可能有兴趣检查您的置信水平以及您对OOP的了解程度.


Mix*_*els 16

技术部分已经在其他答案中得到了很好的介绍,主要是:
"他错了,他不懂东西,请他加入SO并将其全部清除:)"

我想谈谈这个事实(在其他答案中已经提到过),这可能是一个压力问题,并且是许多访调员了解更多关于你的重要工具,以及你如何应对困难和不寻常的情况.通过给你错误的代码,他可能想看看你是否反驳过.要知道你是否有信心在类似的情况下与你的老年人站在一起.

PS:我不知道为什么,但我感觉面试官已经阅读了这篇文章.


Abh*_*hra 13

抽象类无法实例化,但可以进行子类化.请参阅此链接

最好的例子是

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

calc是指GregorianCalendar类的类实例为"GregorianCalendar extends Calendar "

事实上,匿名内部类型 允许您创建抽象类的无名子类及其实例.


Gle*_*est 11

技术答案

抽象类无法实例化 - 这是定义和设计.

来自JLS,第8章.类:

命名类可以声明为abstract(第8.1.1.1节),如果未完全实现,则必须声明为abstract; 这样的类不能实例化,但可以通过子类扩展.

来自JSE 6的Java doc for Classes.newInstance():

InstantiationException - 如果此Class表示抽象类,接口,数组类,基元类型或void; 或者如果该类没有无效的构造函数; 或者如果实例化因某些其他原因而失败.

当然,您可以实例化抽象类的具体子类(包括匿名子类),并且还可以对抽象类型的对象引用进行类型转换.

不同的角度 - Teamplay和社交智能:

当我们处理复杂的技术和法律规范时,这种技术上的误解在现实世界中经常发生.

"人员技能"在这里比"技术技能"更重要.如果竞争激烈并且积极地试图证明你的观点,那么理论上你可能是正确的,但你也可以在战斗/破坏"面子"/创造一个敌人而不是它的价值时做更多的伤害.在解决分歧方面需要和解和理解.谁知道 - 也许你是"两个都正确"但是对于条款的工作方式略有不同?

谁知道 - 尽管不太可能,面试官有可能故意引入一个小冲突/误解,让你陷入困境,看看你的情绪和社交行为.与同事保持亲切和建设性,遵循老年人的建议,并在面试结束后通过电子邮件或电话解决任何挑战/误解.表明你是有动力和注重细节的.


iTe*_*ech 7

这是一个公认的事实,abstract class可以为大家回答被实例化.

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

因此,如果您反编译此Java类,您将找到如下代码:

我的课

abstract class my { 
    public void mymethod() 
    { 
        System.out.print("Abstract"); 
    }
} 
Run Code Online (Sandbox Code Playgroud)

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

class poly$1 extends my 
{
} 
Run Code Online (Sandbox Code Playgroud)

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();
    }
}
Run Code Online (Sandbox Code Playgroud)


Pri*_*ara 5

关于抽象类

  • 无法创建抽象类的对象
  • 可以创建变量(可以表现得像数据类型)
  • 如果子级不能重写父级的至少一个抽象方法,则子级也将变为抽象方法
  • 没有子类,抽象类就没用了

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