繼承關係
兩個類之間存在三種關係:
- 依賴,uses-a,如果一個類的方法操縱另一個對象,我們就說一個類依賴於另一個類。
- 彙總(關聯),has-a,一個對象包含另外一個對象,彙總關係意味著類A的對象包含類B的對象。
- 繼承,is-a,如果兩個類之間存在明顯的is-a(是)關係,例如每個經理都是僱員,那這兩個類有繼承關係。
例如:
class Manager extends Employee{ ......}
Manager繼承了Employee類,繼承可以重寫超類的方法,也可以添加方法,即子類比超類擁有的功能更加豐富。方法重寫當子類重寫超類的方法時,也可以調用超類的同名方法,只需要使用super.method()。要注意,重寫的方法不可低於超類方法的存取權限!例如:
//重寫getSalary方法public double getSalary(){double baseSalary = super.getSalary();//調用了超類的getSalary方法return baseSalary + bonus;}
子類重寫了getSalary()方法,也調用了超類的同名方法。
另外,super()方法也可以在構造器中使用,以便調用超類的構造器方法。要注意的是super()方法必須是子類構造器的第一條語句。否則編譯器會給出Constructor call must be the first statement in a constructor的錯誤提醒。例子見最後大例子。多態和動態綁定一個對象(例如下例中的e)能夠引用多種實際類型的現象稱為多態,在運行時能夠自動的選擇調用那個方法的想象成為動態綁定。Java不支援多重繼承,僅支援單繼承。例如下面的大例子中,Emplyee類型的e可以引用Emplyee類型,Manager類型以及Boss類型的對象,當調用e.getSalary()的時候,編譯器知道具體的e的實際類型,從而準確的調用該實際類型類的getSalary方法,如果不存在,那就調用其超類的該方法,這就是動態綁定。final阻止繼承。
class Employee{......public final String getName(){return name;}......}final class Manager extends Employee{......}
如上例中,Manager類不可以再被繼承了,而getName方法也不可被子類重寫。
強制類型轉換進行強制類型轉換的原因:在暫時忽視對象的實際類型之後,使用對象的全部功能。僅可以在繼承鏈上從上向下進行轉換,如把實際類型是Manager的Employee類型的staff[1]轉換成Manager類型。
Manager man = (Manager)staff[1];
例子總結性的大例子:
package com.xujin;public class Test {public static void main(String[] args) {Employee[] staff = new Employee[3];staff[0] = new Employee("Bob", 1000);staff[1] = new Manager("Jim", 5000, 1000);staff[2] = new Boss("Alice", 7000, 1000, 10000);for(Employee e : staff)System.out.println("class name:" + e.getClass().getName() + "\tid:" + e.getId() + "\tname:" + e.getName() + "\tsalary:" + e.getSalary());Manager man = (Manager)staff[1];Boss boss = (Boss)staff[2];System.out.println(man.getBonus());//類型轉換後就可以使用實際類型的全部功能System.out.println(boss.getAward());//ClassCastException異常,不允許進行繼承鏈上的從上到下的轉換//Boss myBoss = (Boss)staff[0];//把instaceof運算子和類型轉換組合起來,避免異常if(staff[0] instanceof Boss){System.out.println("staff[0] is a instace of Boss");Boss myBoss = (Boss) staff[0];}else System.out.println("staff[0] isn't a instace of Boss");if(staff[2] instanceof Boss){System.out.println("staff[2] is a instace of Boss");}else System.out.println("staff[2] isn't a instace of Boss");}}class Employee{public Employee(String name){this.name = name;id = nextId;nextId++;}public Employee(String name, double salary){this(name);//調用另一構造器this.salary = salary;}//定義訪問器方法public final String getName(){return name;}public double getSalary(){return salary;}public final int getId(){return id;}//定義更改器方法public final void setName(String name){this.name = name;}public final void setSalary(double salary){this.salary = salary;}public final void raiseSalary(double percent){this.salary *= (1 + percent);}//定義變數private String name = "";//執行個體域初始化private double salary;private int id;private static int nextId = 1;}class Manager extends Employee{public Manager(String name, double salary, double bonus){super(name, salary);//super在構造器中的使用,可以調用超類的構造器setBonus(bonus);}public double getBonus(){return bonus;}//重寫getSalary方法public double getSalary(){double baseSalary = super.getSalary();//調用了超類的getSalary方法return baseSalary + bonus;}public void setBonus(double bonus){this.bonus = bonus;}private double bonus;}final class Boss extends Manager{public Boss(String name, double salary, double bonus, double award){super(name, salary, bonus);this.award = award;}//重寫getSalary方法public double getSalary(){double baseSalary = super.getSalary();//調用了超類的getSalary方法return baseSalary + award;}public double getAward(){return award;}private double award;}
抽象類別最後,闡述一下抽象類別的概念。抽象類別就是一個專門用來擴充的祖先類,抽象類別本身不能定義一個該類的對象,即抽象類別不能被執行個體化。
Person p = new Student("joun", 17, 6000);
這裡p是一個person類型的變數,但是它引用了Student類型的執行個體。
抽象類別中的方法有兩種,一種是普通的,和一般類中的方法一樣,另一種是抽象方法,起一個佔位的作用,將來子類繼承會實現這種方法。類即使不含抽象方法,也可以將類聲明為抽象方法。
抽象類別的抽象方法可以用來實現多態性,例如下例中在抽象類別中定義了一個getFee()方法,兩個子類Employee和Student分別實現了它,但是用了不同的實現方法,當通過Person類型的p調用getFee()方法時,就會根據p的實際類型來調用確定的方法。
package com.xujin;public class Test {public static void main(String[] args) {Person[] people = new Person[2];people[0] = new Employee("Bod", 34, 5000);people[1] = new Student("Joun", 17, 6000);for(Person p: people){System.out.print("Name:" + p.getName() + "\tAge:" + p.getAge() +"\tDescription:" + p.getDescription() + "\t");if(p instanceof Employee){System.out.println(((Employee) p).getFee());}else if(p instanceof Student)System.out.println(((Student) p).getFee());}}}abstract class Person{public Person(String name, int age){this.name = name;this.age = age;}public abstract String getDescription();public final String getName(){return this.name;}public final void setName(String name){this.name = name;}public final int getAge(){return this.age;}public final void setAge(int age){this.age = age;}private String name;private int age;}class Employee extends Person{public Employee(String name, int age, double fee){super(name, age);id = nextId;nextId++;this.fee = fee;}//定義Person抽象類別的抽象方法public String getDescription(){return "This is an employee. class name:" + this.getClass().getName();}//定義訪問器方法public double getFee(){return fee * 2;}public final int getId(){return id;}//定義更改器方法public final void setFee(double salary){this.fee = fee;}//定義變數private double fee;private int id;private static int nextId = 1;}class Student extends Person{public Student(String name, int age, double fee){super(name, age);this.fee = fee;}public String getDescription(){return "This is a student. class name:" + this.getClass().getName();}public double getFee(){return this.fee;}public void setFee(double fee){this.fee = fee;}private double fee;}
結果: