在面向?qū)ο蟮母拍钪幸呗械膶?duì)象都是通過(guò)類(lèi)來(lái)描繪的滚躯,但是反過(guò)來(lái),并不是所有的類(lèi)都是用來(lái)描繪對(duì)象的,如果一個(gè)類(lèi)中沒(méi)有包含足夠的信息來(lái)描繪一個(gè)具體的對(duì)象靴患,這樣的類(lèi)就是抽象類(lèi)。
抽象類(lèi)除了不能實(shí)例化對(duì)象之外况脆,類(lèi)的其它功能依然存在看铆,成員變量悄但、成員方法和構(gòu)造方法的訪問(wèn)方式和普通類(lèi)一樣助泽。
由于抽象類(lèi)不能實(shí)例化對(duì)象诫睬,所以抽象類(lèi)必須被繼承,才能被使用。也是因?yàn)檫@個(gè)原因,通常在設(shè)計(jì)階段決定要不要設(shè)計(jì)抽象類(lèi)。
父類(lèi)包含了子類(lèi)集合的常見(jiàn)的方法,但是由于父類(lèi)本身是抽象的,所以不能使用這些方法。
在Java中抽象類(lèi)表示的是一種繼承關(guān)系,一個(gè)類(lèi)只能繼承一個(gè)抽象類(lèi)锡垄,而一個(gè)類(lèi)卻可以實(shí)現(xiàn)多個(gè)接口。
抽象類(lèi)
在Java語(yǔ)言中使用abstract class來(lái)定義抽象類(lèi)。如下實(shí)例:
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 類(lèi)沒(méi)有什么不同距境,盡管該類(lèi)是抽象類(lèi),但是它仍然有 3 個(gè)成員變量后控,7 個(gè)成員方法和 1 個(gè)構(gòu)造方法张抄。 現(xiàn)在如果你嘗試如下的例子:
public class AbstractDemo
{
public static void main(String [] args)
{
/* 以下是不允許的泽台,會(huì)引發(fā)錯(cuò)誤 */
Employee e = new Employee("George W.", "Houston, TX", 43);
System.out.println("\n Call mailCheck using Employee reference--");
e.mailCheck();
}
}
編譯的時(shí)候報(bào)錯(cuò):
AbstractDemo.java:4: 錯(cuò)誤: Employee是抽象的; 無(wú)法實(shí)例化
Employee e = new Employee("George W.", "Houston, TX", 43); ^
1 個(gè)錯(cuò)誤
繼承抽象類(lèi)
我們能通過(guò)一般的方法繼承Employee類(lèi):
public class Salary extends Employee
{
private double salary; //Annual 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;
}
}
盡管我們不能實(shí)例化一個(gè) Employee 類(lèi)的對(duì)象样眠,但是如果我們實(shí)例化一個(gè) Salary 類(lèi)對(duì)象辫秧,該對(duì)象將從 Employee 類(lèi)繼承 7 個(gè)成員方法,且通過(guò)該方法可以設(shè)置或獲取三個(gè)成員變量。
public class AbstractTestDemo {
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();
}
}
編譯后的結(jié)果為:
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
抽象方法
如果你想設(shè)計(jì)這樣一個(gè)類(lèi)植旧,該類(lèi)包含一個(gè)特別的成員方法听皿,該方法的具體實(shí)現(xiàn)由它的子類(lèi)確定尉姨,那么你可以在父類(lèi)中聲明該方法為抽象方法。
Abstract 關(guān)鍵字同樣可以用來(lái)聲明抽象方法吗冤,抽象方法只包含一個(gè)方法名又厉,而沒(méi)有方法體。
抽象方法沒(méi)有定義椎瘟,方法名后面直接跟一個(gè)分號(hào)覆致,而不是花括號(hào)。
public abstract class EmployeTest {
private String name;
private String address;
private int number;
public abstract double computePay();
// 其余代碼
}
聲明抽象方法會(huì)造成以下兩個(gè)結(jié)果:
- 如果一個(gè)類(lèi)包含抽象方法肺蔚,那么該類(lèi)必須是抽象類(lèi)煌妈。
- 任何子類(lèi)必須重寫(xiě)父類(lèi)的抽象方法,或者聲明自身為抽象類(lèi)宣羊。
繼承抽象方法的子類(lèi)必須重寫(xiě)該方法璧诵。否則,該子類(lèi)也必須聲明為抽象類(lèi)段只。最終,必須有子類(lèi)實(shí)現(xiàn)該抽象方法鉴扫,否則赞枕,從最初的父類(lèi)到最終的子類(lèi)都不能用來(lái)實(shí)例化對(duì)象。
如果SalaryTest類(lèi)繼承了EmployeeTest類(lèi),那么它必須實(shí)現(xiàn)computePay()方法:
public class SalaryTest extends EmployeTest {
private double salary; // Annual salary
public double computePay() {
System.out.println("Computing salary pay for " + getName());
return salary / 52;
}
// 其余代碼
}
抽象類(lèi)總結(jié)規(guī)定
- 抽象類(lèi)不能被實(shí)例化(初學(xué)者很容易犯的錯(cuò))炕婶,如果被實(shí)例化姐赡,就會(huì)報(bào)錯(cuò),編譯無(wú)法通過(guò)柠掂。只有抽象類(lèi)的非抽象子類(lèi)可以創(chuàng)建對(duì)象项滑。
- 抽象類(lèi)中不一定包含抽象方法,但是有抽象方法的類(lèi)必定是抽象類(lèi)涯贞。
- 抽象類(lèi)中的抽象方法只是聲明枪狂,不包含方法體,就是不給出方法的具體實(shí)現(xiàn)也就是方法的具體功能宋渔。
- 構(gòu)造方法州疾,類(lèi)方法(用 static 修飾的方法)不能聲明為抽象方法。
- 抽象類(lèi)的子類(lèi)必須給出抽象類(lèi)中的抽象方法的具體實(shí)現(xiàn)皇拣,除非該子類(lèi)也是抽象類(lèi)严蓖。
這個(gè)類(lèi)似于iOS中OC的代理方法,不同的是代理方法被繼承之后還是代理方法氧急。而Java中的這個(gè)抽象類(lèi) 被繼承后只要實(shí)現(xiàn)了抽象方法就可以了颗胡。類(lèi)還是單獨(dú)的類(lèi)唯一和抽象類(lèi)相關(guān)的也就是抽象方法了。
源地址:Java 抽象類(lèi)
github地址:Java學(xué)習(xí)