Java抽象


在面向对象的编程中,抽象是向用户隐藏实现细节的过程,只给用户提供方法而不是实现细节。换句话说,用户将获得有关对象做什么而不是对象如何工作的信息。

在Java中,抽象是使用Abstract类和接口实现的。

抽象类


在声明中包含abstract关键字的类被称为抽象类:

  • 抽象类可能包含也可能不包含抽象方法 ,抽象方法是只有声明没有方法体的方法;

  • 但是,如果该类至少包含一个抽象方法,则该类一定要被声明为抽象;

  • 如果类被声明为抽象,则无法实例化

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

要创建一个抽象类,只需将类声明为abstract,以下是抽象类的示例:

/* 文件名 : Employee.java */
public abstract class Employee {
    private String name;
    private String address;
    private int number;

    public Employee(String name, String address, int number) {
        System.out.println("Constructing an Employee");
        this.name = name;
        this.address = address;
        this.number = number;
    }
   
    public double computePay() {
     System.out.println("Inside Employee computePay");
     return 0.0;
    }
   
    public void mailCheck() {
        System.out.println("Mailing a check to " + this.name + " " + this.address);
    }

    public String toString() {
        return name + " " + address + " " + number;
    }

    public String getName() {
        return name;
    }
 
    public String getAddress() {
        return address;
    }
   
    public void setAddress(String newAddress) {
        address = newAddress;
    }
 
    public int getNumber() {
        return number;
    }
}

可以观察到,除抽象方法外,Employee类与Java普通的类相同。该类现在是抽象的,但它仍然具有三个字段,七个方法和一个构造方法。

现在,可以尝试通过以下方式实例化Employee类:

/* 文件名 : AbstractDemo.java */
public class AbstractDemo {

    public static void main(String [] args) {
        /* 以下是不允许的,会引起error */
        Employee e = new Employee("George W.", "Houston, TX", 43);
        System.out.println("\n Call mailCheck using Employee reference--");
        e.mailCheck();
    }
}

当编译上面的类时,它会给出以下错误:

Employee.java:46: Employee is abstract; cannot be instantiated
        Employee e = new Employee("George W.", "Houston, TX", 43);
                   ^
1 error

继承抽象类


我们可以通过以下方式继承Employee类的属性:

/* 文件名 : Salary.java */
public class Salary extends Employee {
    private double salary;   //年薪
   
    public Salary(String name, String address, int number, double salary) {
        super(name, address, number);
        setSalary(salary);
    }
   
    public void mailCheck() {
        System.out.println("Within mailCheck of Salary class ");
        System.out.println("Mailing check to " + getName() + " with salary " + salary);
    }
 
    public double getSalary() {
        return salary;
    }
   
    public void setSalary(double newSalary) {
        if(newSalary >= 0.0) {
            salary = newSalary;
        }
    }
   
    public double computePay() {
        System.out.println("Computing salary pay for " + getName());
        return salary/52;
    }
}

在这里,不能实例化Employee类,但是可以实例化Salary类,并且可以使用此实例访问Employee类的三个字段和七个方法,如下所示:

/* 文件名 : AbstractDemo.java */
public class AbstractDemo {

    public static void main(String [] args) {
        Salary s = new Salary("Mohd Mohtashim", "Ambehta, UP", 3, 3600.00);
        Employee e = new Salary("John Adams", "Boston, MA", 2, 2400.00);
        System.out.println("Call mailCheck using Salary reference --");
        s.mailCheck();
        System.out.println("\n Call mailCheck using Employee reference--");
        e.mailCheck();
    }
}

这将产生以下结果:

Constructing an Employee
Constructing an Employee
Call mailCheck using Salary reference --
Within mailCheck of Salary class 
Mailing check to Mohd Mohtashim with salary 3600.0

 Call mailCheck using Employee reference--
Within mailCheck of Salary class 
Mailing check to John Adams with salary 2400.0

抽象方法


如果希望一个类包含一个特定的方法,但是该方法的实现由子类确定,则可以在父类中将该方法声明为abstract:

  • abstract关键字用于将方法声明为抽象;

  • 必须在方法声明中把abstract关键字放在方法名之前;

  • 抽象方法包含方法签名,但不包含方法体;

  • 抽象方法的末尾是一个半角分号(;),而不是大括号。

以下是抽象方法的示例:

public abstract class Employee {
    private String name;
    private String address;
    private int number;
   
    public abstract double computePay();
    //剩余的类定义
}

将方法声明为抽象有两个结果:

  • 包含它的类必须声明为抽象;

  • 任何继承当前类的类都必须重写abstract方法或将其声明为abstract。

注意:最终,后代类必须实现abstract方法,否则将拥有无法实例化的抽象类的层次结构。

假设Salary类继承了Employee类,则应实现computePay()方法如下:

/* 文件名 : Salary.java */
public class Salary extends Employee {
    private double salary;   //年薪
  
    public double computePay() {
        System.out.println("Computing salary pay for " + getName());
        return salary/52;
    }
    //剩余的类定义
}