Java中的抽象类

269 java oop abstract-class interface

什么是Java中的"抽象类"?

Ima*_*ist 339

抽象类是一个无法实例化的类.通过创建可以实例化的继承子类来使用抽象类.抽象类为继承子类做了一些事情:

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

请注意,"abstractMethod()"没有任何方法体.因此,您无法执行以下操作:

public class ImplementingClass extends AbstractClass
{
    // ERROR!
}
Run Code Online (Sandbox Code Playgroud)

没有方法可以实现abstractMethod()!因此,JVM无法知道它应该做什么时应该做什么new ImplementingClass().abstractMethod().

这是正确的ImplementingClass.

public class ImplementingClass extends AbstractClass
{
    public void abstractMethod() { System.out.print("abstractMethod()"); }
}
Run Code Online (Sandbox Code Playgroud)

请注意,您不必定义implementedMethod()finalMethod().他们已经定义了AbstractClass.

这是另一个正确的ImplementingClass.

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

在这种情况下,您已被覆盖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!"); }
}
Run Code Online (Sandbox Code Playgroud)

你不能这样做是因为finalMethod()in 的实现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()"); }
}
Run Code Online (Sandbox Code Playgroud)

现在你可以在某处编写另一种方法.

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

请注意,即使我们声明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();
Run Code Online (Sandbox Code Playgroud)

最后,您无法执行以下操作:

public class ImplementingClass extends AbstractClass, SomeOtherAbstractClass
{
    ... // implementation
}
Run Code Online (Sandbox Code Playgroud)

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

public class ImplementingClass extends AbstractClass implements InterfaceA, InterfaceB
{
    ... // implementation
}
Run Code Online (Sandbox Code Playgroud)

这是一个示例界面:

interface InterfaceA
{
    void interfaceMethod();
}
Run Code Online (Sandbox Code Playgroud)

这基本上与以下相同:

abstract public class InterfaceA
{
    abstract public void interfaceMethod();
}
Run Code Online (Sandbox Code Playgroud)

唯一的区别是第二种方式不会让编译器知道它实际上是一个接口.如果您希望人们只实现您的界面而没有其他人,那么这将非常有用.但是,作为一般初学者的经验法则,如果您的抽象类只有抽象方法,那么您应该将它作为一个接口.

以下是非法的:

interface InterfaceB
{
    void interfaceMethod() { System.out.print("ERROR!"); }
}
Run Code Online (Sandbox Code Playgroud)

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

  • @Imagist -1表示对c.implementedMethod()语句的错误描述; //打印"implementedMethod()",它将打印"Overriden!" 总是 (5认同)
  • @SachinKumar为什么要`c.implementedMethod()`print"Overriden!"?`SecondImplementingClass`不会覆盖`implementedMethod()`. (5认同)
  • @Sachin我浪费了半小时的时间来理解它为什么要打印"implementedMethod()"然后我看到了你的评论.有没有改变java或其他人只是忽略了错误? (2认同)

Dan*_*ski 72

在以下条件下,Java类变为抽象类:

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

public abstract void myMethod()
Run Code Online (Sandbox Code Playgroud)

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

2.该类被标记为抽象:

abstract class MyClass
Run Code Online (Sandbox Code Playgroud)

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

常用:

抽象类的一个常见用途是提供类似于接口的类的大纲.但是与接口不同,它已经可以提供功能,即类的某些部分已经实现,而某些部分只是通过方法声明来概述.("抽象")

抽象类无法实例化,但您可以基于抽象类创建具体类,然后可以对其进行实例化.为此,您必须从抽象类继承并覆盖抽象方法,即实现它们.

  • 同意,建议不是很正确,或写得很好,它的格式很好. (2认同)

Jus*_*ode 22

使用abstract关键字声明的类称为abstract class.抽象是隐藏数据实现细节并仅向用户显示功能的过程.通过抽象,您可以专注于对象的作用而不是对象的作用.

抽象类的主要内容

  • 抽象类可能包含也可能不包含抽象方法.可以使用非抽象方法.

    抽象方法是在没有实现的情况下声明的方法(没有大括号,后跟分号),如下所示:

    例如: abstract void moveTo(double deltaX, double deltaY);

  • 如果一个类至少有一个抽象方法,那么该类必须是抽象的

  • 可能无法实例化抽象类(不允许创建Abstract类的对象)

  • 要使用抽象类,必须从另一个类继承它.为其中的所有抽象方法提供实现.

  • 如果继承了抽象类,则必须为其中的所有抽象方法提供实现.

声明抽象类abstract在声明期间在类之前 指定关键字使其成为抽象.看看下面的代码:

abstract class AbstractDemo{ }
Run Code Online (Sandbox Code Playgroud)

声明抽象方法abstract在声明期间在方法之前 指定关键字使其成为抽象.看看下面的代码,

abstract void moveTo();//no body
Run Code Online (Sandbox Code Playgroud)

为什么我们需要抽象类

在面向对象的绘图应用程序中,您可以绘制圆形,矩形,线条,贝塞尔曲线和许多其他图形对象.这些对象都有一些共同的状态(对于前 - :位置,方向,线条颜色,填充颜色)和行为(对于前 - :moveTo,旋转,调整大小,绘制).对于所有图形对象,这些状态和行为中的一些是相同的(例如:填充颜色,位置和moveTo).其他需要不同的实现(例如:调整大小或绘制).所有图形对象必须能够自己绘制或调整大小,它们的工作方式不同.

这是抽象超类的完美情况.你可以利用的类似性,并宣布所有图形对象从同一抽象父对象继承(用于例如:GraphicObject),如图下图. 在此输入图像描述

首先,声明一个抽象类,GraphicObject,以提供完全被所有的子类,如当前位置和moveTo方法共享成员变量和方法.GraphicObject还声明了抽象方法,例如draw或resize,它们需要由所有子类实现,但必须以不同的方式实现.本GraphicObject类可以是这个样子:

abstract class GraphicObject {

  void moveTo(int x, int y) {
    // Inside this method we have to change the position of the graphic 
    // object according to x,y     
    // This is the same in every GraphicObject. Then we can implement here. 
  }

  abstract void draw(); // But every GraphicObject drawing case is 
                        // unique, not common. Then we have to create that 
                        // case inside each class. Then create these    
                        // methods as abstract 
  abstract void resize();
}
Run Code Online (Sandbox Code Playgroud)

在子类中使用抽象方法 每个非抽象子类(GraphicObject例如CircleRectangle)必须提供drawresize方法的实现.

class Circle extends GraphicObject {
  void draw() {
    //Add to some implementation here
  }
  void resize() {
    //Add to some implementation here   
  }
}
class Rectangle extends GraphicObject {
  void draw() {
    //Add to some implementation here
  }
  void resize() {
    //Add to some implementation here
  }
}
Run Code Online (Sandbox Code Playgroud)

main方法内部,您可以调用所有方法,如下所示:

public static void main(String args[]){
   GraphicObject c = new Circle();
   c.draw();
   c.resize();
   c.moveTo(4,5);   
}
Run Code Online (Sandbox Code Playgroud)

如何在Java中实现抽象

有两种方法可以在java中实现抽象

  • 抽象类(0到100%)
  • 界面(100%)

具有构造函数,数据成员,方法等的抽象类

abstract class GraphicObject {

  GraphicObject (){
    System.out.println("GraphicObject  is created");
  }
  void moveTo(int y, int x) {
       System.out.println("Change position according to "+ x+ " and " + y);
  }
  abstract void draw();
}

class Circle extends GraphicObject {
  void draw() {
    System.out.println("Draw the Circle");
  }
}

class TestAbstract {  
 public static void main(String args[]){

   GraphicObject  grObj = new Circle ();
   grObj.draw();
   grObj.moveTo(4,6);
 }
}
Run Code Online (Sandbox Code Playgroud)

输出:

GraphicObject  is created
Draw the Circle
Change position according to 6 and 4
Run Code Online (Sandbox Code Playgroud)

记住两个规则:

  • 如果类具有很少的抽象方法和几个具体方法,则将其声明为abstract类.

  • 如果类只有抽象方法,则将其声明为interface.

参考文献:


Noo*_*ilk 4

它是一个无法实例化的类,并强制实现类可能实现它概述的抽象方法。