Java抽象类

时间:2020-01-09 10:34:46  来源:igfitidea点击:

Java中的抽象类是使用abstract关键字声明的类。抽象类可以具有常规方法(带有方法主体的方法)以及抽象方法(没有方法主体并且具有抽象说明符的方法)。

Java抽象类的一般形式

abstract class className{
  ..
  ..
}

什么时候需要抽象类

在为应用程序设计类时,我们可能会遇到这样的情况:超类可以为很少的方法提供常规结构和通用实现,而方法的实现留给实现不同的子类。

子类必须实现的方法在超类中指定为抽象方法。子类必须提供在父类中声明为抽象的方法的实现。

Java抽象方法的一般形式如下:

abstract type methodName(method_arguments);

抽象方法中没有方法主体,子类有责任覆盖抽象方法并提供实现。

Java示例中的抽象类

假设我们必须设计付款功能,其中必须提供现金和信用卡付款功能,并且需要捕获客户详细信息,例如姓名,地址。

在这里捕获客户详细信息很常见,但是付款方式不同。在这种情况下,可以使用必须由子类实现的abstract doPayment()方法创建一个抽象类,并将公共代码保留在抽象类中,以供所有子类使用。

public abstract class Payment {
  private String customerName;
  private String customerAddress;
  public Payment() {
    
  }
  public Payment(String customerName, String customerAddress){
    this.customerName = customerName;
    this.customerAddress = customerAddress;
  }
  public void printCustDetails() {
    System.out.println("Name- " + customerName + " Address- " + customerAddress);
  }
  // abstract method
  abstract void doPayment(double amount); 
}
// childclass-1
class CashPayment extends Payment {
  CashPayment(String customerName, String customerAddress){
    super(customerName, customerAddress);
  }
  @Override
  public void doPayment(double amount) {
    System.out.println("In child class CashPayment, payment of - " + amount);
    printCustDetails();
  }
}
//childclass-2
class CCPayment extends Payment {
  CCPayment(String customerName, String customerAddress){
    super(customerName, customerAddress);
  }
  @Override
  public void doPayment(double amount) {
    System.out.println("In child class CCPayment, payment of - " + amount);
    printCustDetails();
  }
}

用于运行代码的类

public class MainClass {

  public static void main(String[] args) {
    // super class reference
    Payment payment;
    // holding CashPayment instance
    payment = new CashPayment("Amy", "5th ave, NYC");
    payment.doPayment(56.25);
    // holding CCPayment instance
    payment = new CCPayment("Parker", "Burnsville, NC");
    payment.doPayment(67.89);
  }
}

输出:

In child class CashPayment, payment of - 56.25
Name- Amy Address- 5th ave, NYC
In child class CCPayment, payment of - 67.89
Name- Parker Address- Burnsville, NC

在该示例中,有一个抽象类Payment,它具有一个用于通用实现的具体方法printCustDetails()和一个抽象方法doPayment()。子类CashPayment和CCPayment均根据其要求实现了抽象方法。这两个类都调用通用方法来打印客户详细信息。

在Java中使用Abstract类时的约束

  • 抽象类无法实例化。在上面的示例中,Payment是一个抽象类,尝试实例化它-Payment payment = new Payment();导致编译时错误"无法实例化付款类型"。

  • 虽然无法实例化Abstract类,但是可以创建Abstract类的对象引用。该对象引用可以保存子类对象。这就是Java中的抽象类如何帮助实现运行时多态性。在上面的示例中,我们可以看到创建了抽象类Payment的引用-Payment Payment;它引用子类对象并调用适当的doPayment()方法。

  • 如果类中有任何抽象方法,则必须将一个类声明为抽象,否则会出现编译时错误"类型必须是抽象类才能定义抽象方法"。

  • 扩展抽象类的子类必须实现超类的所有抽象方法,否则,该类也应声明为抽象类。例如

abstract class ParentClass {
  abstract void display();
  abstract void add();
}

class ChildClass extends ParentClass {
  public void add() {
    System.out.println("In add method");
  }
}

此处,子类未实现抽象方法display()之一,这将导致编译时错误" ChildClass类型必须实现继承的抽象方法ParentClass.display()"。如果childClass未实现display()方法,则还应将其声明为abstract。

abstract class ChildClass extends ParentClass {
  public void add() {
    System.out.println("In add method");
  }
}
  • 类中的构造函数不能声明为抽象。摘要是构造函数的非法修饰符。任何静态方法也不能抽象。

  • 一个类可以声明为抽象,也可以声明为final,而不是两者都声明。

没有抽象方法的抽象类

我们可以创建一个没有抽象方法的Java抽象类,即所有方法都是具体的,并在其中实现。这是创建只能实例化的类的一种方法。

abstract class ParentClass {
  public void display() {
    System.out.println("In parent class method");
  }
}

class ChildClass extends ParentClass {
  public void add() {
    System.out.println("In add method");
  }
}

public class MainClass {

  public static void main(String[] args) {
    ChildClass obj = new ChildClass();
    obj.display();
    obj.add();
  }
}

输出:

In parent class method
In add method

抽象类与接口的比较

Java中的抽象类类似于接口。我们无法实例化它们,它们可能包含使用或者不使用实现声明的方法的混合。
但是,使用抽象类,我们可以声明非静态和最终字段。使用接口,所有字段都将自动成为公共字段,静态字段和最终字段。
在抽象类中,我们可以定义公共,受保护的和私有的具体方法。在接口中,我们声明或者定义的所有方法(作为默认方法)都是公共的。

如果实现接口的类未实现该接口的所有方法,则必须将该类声明为抽象。

public interface Payment {
  void doPayment(double amount);
  void add(int a, int b);
}

abstract class TestClass implements Payment{
  @Override
  public void doPayment(double amount) {
    System.out.println("In payment method");    
  }
}

由于TestClass并未实现接口的两种方法,因此应将其声明为抽象类,否则会出现错误" TestClass类型必须实现继承的抽象方法Payment.add(int,int)"。