Java 中的抽象类

2022-08-31 05:13:57

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


答案 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!
}

没有实现的方法!因此,JVM 无法知道当它得到类似 .abstractMethod()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!"); }
}

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

现在,您还可以实现两次抽象类:

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

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

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

// 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!"); }
}

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


答案 2

在以下情况下,Java 类将变为抽象:

1. 至少有一种方法被标记为抽象:

public abstract void myMethod()

在这种情况下,编译器会强制您将整个类标记为抽象。

2. 该类被标记为抽象:

abstract class MyClass

如前所述:如果你有一个抽象方法,编译器会强制你将整个类标记为抽象。但是,即使您没有任何抽象方法,您仍然可以将类标记为抽象。

常见用途:

抽象类的常见用法是提供类似于接口的类的轮廓。但与接口不同,它已经可以提供功能,即类的某些部分已实现,某些部分仅使用方法声明进行概述。(“摘要”)

抽象类不能实例化,但可以基于抽象类创建具体类,然后可以实例化该类。为此,您必须从抽象类继承并重写抽象方法,即实现它们。