Java 中的抽象类

新手上路,请多包涵

什么是 Java 中的“抽象类”?

原文由 keyur 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 416
1 个回答

抽象类是不能实例化的类。通过创建 可以 实例化的继承子类来使用抽象类。抽象类为继承子类做一些事情:

  1. 定义继承子类可以使用的方法。
  2. 定义继承子类必须实现的抽象方法。
  3. 提供一个公共接口,允许子类与所有其他子类互换。

这是一个例子:

 abstract public class AbstractClass
{
    abstract public void abstractMethod();
    public void implementedMethod() { System.out.print("implementedMethod()"); }
    final public void finalMethod() { System.out.print("finalMethod()"); }
}

请注意,“abstractMethod()”没有任何方法体。因此,您不能执行以下操作:

 public class ImplementingClass extends AbstractClass
{
    // ERROR!
}

没有实现 abstractMethod() 的方法!因此,当 JVM 收到类似 new ImplementingClass().abstractMethod() 的内容时,它无法知道它应该做什么。

这是正确的 ImplementingClass

 public class ImplementingClass extends AbstractClass
{
    public void abstractMethod() { System.out.print("abstractMethod()"); }
}

请注意,您不必定义 implementedMethod()finalMethod() 。它们已经由 AbstractClass 定义。

这是另一个正确的 ImplementingClass

 public class ImplementingClass extends AbstractClass
{
    public void abstractMethod() { System.out.print("abstractMethod()"); }
    public void implementedMethod() { System.out.print("Overridden!"); }
}

在这种情况下,您已覆盖 implementedMethod()

但是,由于 final 关键字,以下是不可能的。

 public class ImplementingClass extends AbstractClass
{
    public void abstractMethod() { System.out.print("abstractMethod()"); }
    public void implementedMethod() { System.out.print("Overridden!"); }
    public void finalMethod() { System.out.print("ERROR!"); }
}

你不能这样做,因为 finalMethod()AbstractClass 中的实现被标记为 --- 的最终实现 finalMethod() 将被允许:永远不允许其他实现。

现在你也 可以 实现一个抽象类两次:

 public class ImplementingClass extends AbstractClass
{
    public void abstractMethod() { System.out.print("abstractMethod()"); }
    public void implementedMethod() { System.out.print("Overridden!"); }
}

// In a separate file.
public class SecondImplementingClass extends AbstractClass
{
    public void abstractMethod() { System.out.print("second abstractMethod()"); }
}

现在你可以在某个地方编写另一种方法。

 public tryItOut()
{
    ImplementingClass a = new ImplementingClass();
    AbstractClass b = new ImplementingClass();

    a.abstractMethod();    // prints "abstractMethod()"
    a.implementedMethod(); // prints "Overridden!"     <-- same
    a.finalMethod();       // prints "finalMethod()"

    b.abstractMethod();    // prints "abstractMethod()"
    b.implementedMethod(); // prints "Overridden!"     <-- same
    b.finalMethod();       // prints "finalMethod()"

    SecondImplementingClass c = new SecondImplementingClass();
    AbstractClass d = new SecondImplementingClass();

    c.abstractMethod();    // prints "second abstractMethod()"
    c.implementedMethod(); // prints "implementedMethod()"
    c.finalMethod();       // prints "finalMethod()"

    d.abstractMethod();    // prints "second abstractMethod()"
    d.implementedMethod(); // prints "implementedMethod()"
    d.finalMethod();       // prints "finalMethod()"
}

请注意,即使我们声明了 b 一个 AbstractClass 类型,它也会显示 "Overriden!" 。这是因为我们实例化的对象实际上是一个 ImplementingClass ,其 implementedMethod() 当然被覆盖了。 (您可能已经看到这被称为多态性。)

如果我们希望访问特定于特定子类的成员,我们必须首先向下转换到该子类:

 // Say ImplementingClass also contains uniqueMethod()
// To access it, we use a cast to tell the runtime which type the object is
AbstractClass b = new ImplementingClass();
((ImplementingClass)b).uniqueMethod();

最后,您不能执行以下操作:

 public class ImplementingClass extends AbstractClass, SomeOtherAbstractClass
{
    ... // implementation
}

一次只能延长一个班级。如果你需要扩展多个类,它们必须是接口。你可以这样做:

 public class ImplementingClass extends AbstractClass implements InterfaceA, InterfaceB
{
    ... // implementation
}

这是一个示例界面:

 interface InterfaceA
{
    void interfaceMethod();
}

这与以下内容基本相同:

 abstract public class InterfaceA
{
    abstract public void interfaceMethod();
}

唯一的区别是第二种方式不会让编译器知道它实际上是一个接口。如果您希望人们只实现您的界面而不实现其他界面,这会很有用。然而,作为一般初学者的经验法则,如果你的抽象类只有抽象方法,你应该把它变成一个接口。

以下是非法的:

 interface InterfaceB
{
    void interfaceMethod() { System.out.print("ERROR!"); }
}

您不能在接口中实现方法。这意味着如果您实现两个不同的接口,这些接口中的不同方法就不会发生冲突。由于接口中的所有方法都是抽象的,因此您必须实现该方法,并且由于您的方法是继承树中的唯一实现,因此编译器知道它必须使用您的方法。

原文由 Imagist 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题