【问题标题】:Why cannot use new keyword to initialize abstract class in Java?为什么不能使用 new 关键字在 Java 中初始化抽象类?
【发布时间】:2011-09-07 14:11:19
【问题描述】:

我在某处读到我们无法初始化接口,例如:

interface MyInterface{};

而且下面的代码肯定是非法的:

MyInterface m = new MyInterface();

我记得我读过的文字说:因为new关键字用于为类成员分配内存;所以在接口的情况下,我们只有抽象函数,所以接口中没有什么要分配的;因此,禁止初始化接口。

好的,这对我来说很有意义。

但是在抽象类的情况下,我们可以声明和定义抽象函数,非抽象函数,以及普通变量;那么为什么我们也不允许初始化抽象类呢?因此,我想知道抽象类中的变量(如果有的话)何时以及如何分配内存?

【问题讨论】:

  • 在子类调用super()时分配

标签: java interface new-operator abstract


【解决方案1】:

没有一个对象是“只是”一个抽象类的实例——它总是一个具体类的实例。否则你可以调用抽象方法......并且不会调用任何实现。

抽象类中的变量的分配方式与任何其他类的变量相同,后者恰好是被初始化的实际类的超类——它们“与”来自基本上是层次结构中的其他类。

编辑:澄清一下,这是一个概念限制,就像一个实现限制一样。抽象类通常包含抽象方法,这就是将其抽象化的原因。抽象方法的要点是允许调用者在编译时检查该方法是否存在,即使抽象类不提供实现。 VM 通过防止“仅”抽象类的实例化来确保存在一个实现。

现在抽象类可以用来防止实例化,即使没有任何抽象方法——基本上抽象类的基本点是它是一个不能 直接实例化;只能实例化具体的子类。

【讨论】:

  • @Kerrek SB - 静态成员不属于任何实例。您可以这样称呼它们:例如FileUtils.readFile(fileName)。您不需要实例。
  • @Petar:我知道,但这不是我的意思。我的意思是,您可以选择一个完全合法的类并将其定为“抽象”,并且您不能再实例化它。抽象性是设计的语义属性,而不是物理实现细节的技术结果。这个答案表明抽象性与缺乏某些实现有关。
  • @Kerrek:缺乏方法实现并不是实现的限制——它是一个概念限制。您根本不允许拥有一个可以调用不存在的方法的对象......而抽象类旨在保证方法 will 存在于任何实例上,因为实例必须是一个具体的类。
  • @Jon:嗯,也许我们在说相反的方向。您的观点当然是正确的,但我的反对意见是,您的回答似乎是在暗示缺乏方法实现 导致 类是抽象的(概念上),而我认为是抽象是一个更高层次的概念。毕竟,正如您所说,any 对象实例将使其所有成员函数都存在,否则您无法首先实例化它,您不需要单独的语言概念来确保.摘要应该真的只是意味着“概念上的抽象”......
  • @Kerrek:我想说抽象方法可能是最初创建抽象类概念的最初动机。这么说吧:如果没有抽象方法,你认为不可直接实例化的类的概念是否有足够的价值让它变得有价值?当然,我同意没有抽象方法的抽象类也有用途。
【解决方案2】:

当您说“初始化”时,您实际上是指两个不同的东西:分配和构造。分配是为对象获取内存的过程;构造是将对象本身赋予生命的过程。

如您所见,您的接口类不需要内存。但这不是重点。抽象类不能构造,因为它是……嗯,抽象的。没有抽象类型的object。而且接口是抽象的。

把梅赛德斯想象成一辆抽象的汽车。你可以买一辆奔驰,但你不能买一辆抽象的汽车——它没有语义意义。您可以想象到的任何汽车都必须是混凝土类型的。


编辑:考虑为什么一个类可能是抽象的可能很有用:

  • 因为它被声明为abstract class。这使得它被法令完全抽象,没有给出任何理由。

  • 因为它有抽象成员函数:成员函数没有实现,必须由具体的派生类提供实现。

  • 因为它被声明为interface:这在道德上相当于“所有成员函数都是抽象的,并且没有成员对象”。 (为此使用单独的关键字可以让接口规避单一继承的限制。)

【讨论】:

    【解决方案3】:

    这就是抽象类的意义所在:成为其他类的基类。它专门设计为被实例化。

    大多数抽象类都有抽象方法,而没有实现。如果你实例化了抽象类本身,你会如何调用这样的方法?

    当您使用new 创建抽象类的子类的新实例时,基抽象类所需的内存也将被分配。

    【讨论】:

      【解决方案4】:

      抽象类是尚未完成的类,通常具有抽象成员(尽管它不是强制性的)。所以你不能实例化一个抽象类。这是由语言定义的。

      【讨论】:

        【解决方案5】:

        抽象类是一个被声明为抽象的类——它可能会或可能会 不包括抽象方法。 抽象类不能实例化, 但它们可以被子类化。

        如果一个类包含抽象方法,则该类本身必须是 声明为摘要。

        http://download.oracle.com/javase/tutorial/java/IandI/abstract.html

        【讨论】:

        • @mre 如果他这样做了,他就会明白它总是一个具体类的实例。
        【解决方案6】:

        抽象类未满。它们具有未实现的抽象方法。 如果您尝试调用其中之一会发生什么?

        抽象类的变量被具体实例化的类放在内存中。

        【讨论】:

        • 准确来说抽象类不需要有任何抽象成员:)
        【解决方案7】:

        new 关键字用于extends 抽象类的类时,分配抽象类中的变量。

        因此,如果您没有扩展抽象类的类,它们永远不会被分配。

        【讨论】:

          【解决方案8】:

          当您实例化一个类时,您正在为该类的多个方面分配内存,包括一个用于方法的区域(它比这更复杂)。抽象类没有定义一些方法,所以我们不能把指针指向实际的方法。

          抽象类包含——至少部分地——没有定义的方法。你不能调用它们,因为没有代码可以运行。

          【讨论】:

            【解决方案9】:

            也许带有一些代码的插图可能会有用。

            abstract class AC{
                abstract public void m();
            }
            
            class Main{
                public static void main(String[] a){
                    AC obj = new AC();
                    obj.m();  /* Nothing to execute. */
                }
            }
            

            所以必须禁止这种行为。

            【讨论】:

              【解决方案10】:

              顺便说一句,即使你的接口是空的,你也必须提供一个空的实现:

              可序列化 x = new Serializable(){};

              抽象类也需要空花括号。不过,我想不出会遇到对这些构造的需求。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2010-11-23
                • 2017-05-13
                • 1970-01-01
                相关资源
                最近更新 更多