Java抽象类
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)"。