Java中的抽象类

时间:2009-08-24 06:26:41

标签: java oop interface abstract-class

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

14 个答案:

答案 0 :(得分:326)

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

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

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

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

答案 1 :(得分:71)

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

<强> 1。至少有一种方法被标记为抽象:

public abstract void myMethod()

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

<强> 2。该类被标记为抽象:

abstract class MyClass

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

常用:

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

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

答案 2 :(得分:18)

使用 abstract 关键字声明的类称为abstract class。 抽象是隐藏数据实现细节并仅向用户显示功能的过程。抽象可以让你专注于对象的作用而不是它是如何做的。

抽象类的主要内容

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

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

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

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

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

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

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

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

abstract class AbstractDemo{ }

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

abstract void moveTo();//no body

为什么我们需要抽象类

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

这是抽象超类的完美情境。您可以利用相似性,并声明所有图形对象都从同一个抽象父对象继承(例如GraphicObject),如下图所示。 enter image description here

首先,声明一个抽象类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();
}

在子类中使用抽象方法 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
  }
}

main方法中,您可以调用所有类似的方法:

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

在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);
 }
}

输出:

GraphicObject  is created
Draw the Circle
Change position according to 6 and 4

请记住两条规则:

  • 如果班级的抽象方法很少,具体方法很少, 将其声明为abstract类。

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

参考文献:

答案 3 :(得分:4)

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

答案 4 :(得分:3)

简单地说,您可以将抽象类视为具有更多功能的接口。

您无法实例化一个接口,该接口也适用于抽象类。

在您的界面上,您只需定义方法标题,所有实施者都强制来实施所有。在抽象类上,您还可以定义方法标题,但在此处 - 对于接口的不同 - 您还可以定义方法的主体(通常是默认实现)。此外,当其他类扩展(注意,不实现,因此你也可以只有一个抽象类每个子类)你的抽象类时,他们不会被迫实现抽象类的所有方法,除非你指定了一个抽象方法(在这种情况下,它就像接口一样,你不能定义方法体)。

public abstract class MyAbstractClass{
  public abstract void DoSomething();
}

否则对于抽象类的常规方法,“继承者”可以像往常一样使用默认行为或覆盖它。

示例:

public abstract class MyAbstractClass{

  public int CalculateCost(int amount){
     //do some default calculations
     //this can be overriden by subclasses if needed
  }

  //this MUST be implemented by subclasses
  public abstract void DoSomething();
}

答案 5 :(得分:3)

在这里得到你的答案:

Abstract class vs Interface in Java

Can an abstract class have a final method?

顺便说一句 - 这是你最近问过的问题。考虑一个新问题来建立声誉......

修改

刚才意识到,这个和所引用问题的海报有相同或至少相似的名称,但用户ID总是不同的。所以要么存在一个技术问题,那就是keyur在登录时遇到问题并找到问题的答案,或者这是一种娱乐SO社区的游戏;)

答案 6 :(得分:3)

来自oracle documentation

抽象方法和类:

  

抽象类是一个被声明为abstract的类 - 它可能包含也可能不包含抽象方法

     

抽象类无法实例化,但它们可以是子类

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

abstract void moveTo(double deltaX, double deltaY);

如果一个类包含抽象方法,那么该类本身必须声明为abstract,如:

public abstract class GraphicObject {
   // declare fields
   // declare nonabstract methods
   abstract void draw();
}

当抽象类是子类时,子类通常为其父类中的所有抽象方法提供实现。但是,如果没有,那么子类也必须声明为abstract

由于abstract classesinterfaces相关,请查看以下SE问题:

What is the difference between an interface and abstract class?

How should I have explained the difference between an Interface and an Abstract class?

答案 7 :(得分:1)

解决方案 - 基类(摘要)

public abstract class Place {

String Name;
String Postcode;
String County;
String Area;

Place () {

        }

public static Place make(String Incoming) {
        if (Incoming.length() < 61) return (null);

        String Name = (Incoming.substring(4,26)).trim();
        String County = (Incoming.substring(27,48)).trim();
        String Postcode = (Incoming.substring(48,61)).trim();
        String Area = (Incoming.substring(61)).trim();

        Place created;
        if (Name.equalsIgnoreCase(Area)) {
                created = new Area(Area,County,Postcode);
        } else {
                created = new District(Name,County,Postcode,Area);
        }
        return (created);
        }

public String getName() {
        return (Name);
        }

public String getPostcode() {
        return (Postcode);
        }

public String getCounty() {
        return (County);
        }

public abstract String getArea();

}

答案 8 :(得分:1)

对所有这些帖子的补充很少。

  

有时您可能想申报一个   类,但不知道如何定义   所有属于它的方法   类。例如,您可能想要   声明一个名为 Writer 的类   在其中包含一个名为的成员方法   的写()即可。但是,您不知道如何编写 write(),因为它是   每种类型的作家都有所不同   设备。当然,你计划处理   这通过派生Writer的子类,   如打印机,磁盘,网络和   控制台。

答案 9 :(得分:1)

抽象类不能直接实例化,但必须从中派生才可以使用。如果一个类必须是抽象的,如果它包含抽象方法:直接

abstract class Foo {
    abstract void someMethod();
}

或间接

interface IFoo {
    void someMethod();
}

abstract class Foo2 implements IFoo {
}

但是,类可以是抽象的而不包含抽象方法。它是一种防止直接即时的方法,例如

abstract class Foo3 {
}

class Bar extends Foo3 {

}

Foo3 myVar = new Foo3(); // illegal! class is abstract
Foo3 myVar = new Bar(); // allowed!

后一种抽象类样式可用于创建“类似接口”的类。与接口不同,允许抽象类包含非抽象方法和实例变量。您可以使用它来为扩展类提供一些基本功能。

另一种常见模式是在抽象类中实现主要功能,并在抽象方法中定义算法的一部分,以便由扩展类实现。愚蠢的例子:

abstract class Processor {
    protected abstract int[] filterInput(int[] unfiltered);

    public int process(int[] values) {
        int[] filtered = filterInput(values);
        // do something with filtered input
    }
}

class EvenValues extends Processor {
    protected int[] filterInput(int[] unfiltered) {
        // remove odd numbers
    }
}

class OddValues extends Processor {
    protected int[] filterInput(int[] unfiltered) {
        // remove even numbers
    }
}

答案 10 :(得分:0)

具有混凝土和非混凝土方法的类别,即有和没有身体。

  1. 没有实现的方法必须包含'abstract'关键字。
  2. 无法实例化抽象类。

答案 11 :(得分:0)

抽象类是一个声明为abstract的类 - 它可能包含也可能不包含抽象方法。抽象类不能被实例化,但它们可以被子类化。

换句话说,使用abstract关键字声明的类在java中称为抽象类。它可以有抽象(没有身体的方法)和非抽象方法(带身体的方法)。

重要提示: - 抽象类不能用于实例化对象,它们可用于创建对象引用,因为Java的运行时多态性方法是通过使用超类引用实现的。因此,必须可以创建对抽象类的引用,以便它可以用于指向子类对象。您将在以下示例中看到此功能

abstract class Bike{  
  abstract void run();  
}  

class Honda4 extends Bike{  
    void run(){
        System.out.println("running safely..");
    }  

    public static void main(String args[]){  
       Bike obj = new Honda4();  
       obj.run();  
    }  
} 

答案 12 :(得分:0)

抽象类是一个没有完全实现的类,但为子类提供了一些蓝图。它可以部分实现,因为它包含完全定义的具体方法,但它也可以包含抽象方法。这些是具有签名但没有方法体的方法。任何子类都必须为每个抽象方法定义一个主体,否则它也必须声明为abstract。 因为抽象类不能被实例化,所以它们必须至少由一个子类扩展才能被利用。将抽象类视为泛型类,子类用于填充缺少的信息。

答案 13 :(得分:0)

它什么也不做,只提供一个通用模板即可为其子类共享