import java.util.*; /** * This program demonstrates inheritance. * @version 1.21 2004-02-21 * @author Cay Horstmann */ public class ManagerTest { public static void main(String[] args) { // construct a Manager object Manager boss = new Manager("Carl Cracker", 80000, 1987, 12, 15); boss.setBonus(5000); Employee[] staff = new Employee[3]; // fill the staff array with Manager and Employee objects staff[0] = boss; staff[1] = new Employee("Harry Hacker", 50000, 1989, 10, 1); staff[2] = new Employee("Tommy Tester", 40000, 1990, 3, 15); // print out information about all Employee objects for (Employee e : staff) System.out.println("name=" + e.getName() + ",salary=" + e.getSalary()); } } class Employee { public Employee(String n, double s, int year, int month, int day) { name = n; salary = s; GregorianCalendar calendar = new GregorianCalendar(year, month - 1, day); hireDay = calendar.getTime(); } public String getName() { return name; } public double getSalary() { return salary; } public Date getHireDay() { return hireDay; } public void raiseSalary(double byPercent) { double raise = salary * byPercent / 100; salary += raise; } private String name; private double salary; private Date hireDay; } class Manager extends Employee { /** * @param n the employee's name * @param s the salary * @param year the hire year * @param month the hire month * @param day the hire day */ public Manager(String n, double s, int year, int month, int day) { super(n, s, year, month, day); bonus = 0; } public double getSalary() { double baseSalary = super.getSalary(); return baseSalary + bonus; } public void setBonus(double b) { bonus = b; } private double bonus; }
1)繪製UML類圖,要體現類之間的關係。
java
2)文件第26行e.getSalary(),究竟是調用Manager類的仍是Employee類的getSalary方法?
staff[0] 調用的是Manager類的getSalary方法;
staff[1] 和 staff[2] 調用的是Employee類的getSalary方法。
由於 staff[0] 被幅值爲 Manager 類,子類會覆蓋父類的方法,因此 staff[0] 優先調用Manager類的getSalary方法。函數
3)Manager類的構造函數使用super調用父類的構造函數實現了代碼複用,這樣有什麼好處?爲何不把父類構造函數中的相關代碼複製粘貼到Manager的構造函數中,這樣看起來不是更直觀嗎?
採用super關鍵字調用父類的構造函數能夠減小重複代碼,同時由於子類繼承父類,會繼承到父類中的數據,因此必需要調用父類中的構造函數看父類是如何對本身的數據進行初始化的。因此子類在進行對象初始化時,先調用父類的構造函數,這就是子類的實例化過程。
注意:
一、子類中全部的構造函數都會默認訪問父類中的空參數的構造函數,由於每個子類構造內第一行都有默認的語句super();
二、若父類中沒有空參數的構造函數,那麼子類的構造函數內,必須經過super語句指定要訪問的父類中的構造函數;
三、若子類構造函數中用this來指定調用子類本身的構造函數,那麼被調用的構造函數也同樣會訪問父類中的構造函數。this
for (Employee e : staff) System.out.println("name=" + e.getName() + ",salary=" + e.getSalary()); }
抽象類是爲了把相同的但不肯定的東西的提取出來 ,在Game中都要實行經過循環猜數字這一段代碼,抽象類GuessGame實現了這一方法,那麼遊戲的其餘部分只要直接繼承這個抽象類,再實現其餘方法就能夠了,抽象類構造出一個固定的一組行爲的抽象描述,可是這組行爲卻可以有任意個可能的具體實現方式,這樣改造有利於實現決多重繼承問題。spa
若是繼承自這個抽象類的全部子類都存在這個方法並其的實現都是同樣的時候,則這個方法不須要聲明爲abstract直接實現便可。相反,若是子類存在這一行爲但具體實現是不同的,則應該聲明爲abstract來讓子類實現。
例如:
作一個接口叫作飛行FlyAnimalAction,裏面定義一個方法叫作flying,再定義一個方法叫作eat
作一個類叫作蚊子實現接口,蚊子要實現flying方法,實現本身的eat方法
作一個類叫作蒼蠅實現接口,蒼蠅也要實現flying方法,實現本身的eat方法
你發現全部會飛的動物都要實現這個接口,很麻煩,不如
作一個抽象類FlyAnimal,而後實現上面的接口
在裏面實現flying這個方法,由於大部分的飛行動做是同樣的,而eat方法則繼續寫成抽象方法,由於大部分的動物吃東西是不同的設計
public abstract void print(String text); public abstract void println(String text); public abstract int nextInt();
不變的是go函數,即抽象類中直接實現的方法。code