項目html |
內容java |
這個做業屬於哪一個課程算法 |
<任課教師博客主頁連接> https://www.cnblogs.com/nwnu-daizh/ 編程 |
這個做業的要求在哪裏數組 |
<做業連接地址>https://www.cnblogs.com/nwnu-daizh/p/11605051.html緩存 |
做業學習目標安全 |
深刻理解程序設計中算法與程序的關係;app 深刻理解java程序設計中類與對象的關係;ide 理解OO程序設計的第2個特徵:繼承、多態;函數 學會採用繼承定義類設計程序(重點、難點); 可以分析與設計至少包含3個自定義類的程序; 掌握利用父類定義子類的語法規則及對象使用要求。 |
第一部分:總結第五章理論知識
本章內容:
類、超類和子類;
Object:全部類的超類;
泛型數組列表;
對象包裝器和自動裝箱;
參數數量可變的方法;
枚舉類;
反射;
繼承設計的技巧;
1.繼承:用已有類來構建新類的一種機制。當定義了一個新類繼承了一個類時,這個新類就繼承了這個類的方法和域,同時在新類中添 加新的方法和域以適應新狀況。
2.繼承的特色:具備層次結構 , 子類繼承了父類的域和方法。
3.繼承的優勢:代碼可重用性 父類的域和方法可用於子類 能夠輕鬆定義子類 設計應用程序變得更加簡單。
4.反射是指在程序運行期間發現更多的類及其屬性的能力。
(1)類、超類和子類
1.「is-a」關係是繼承的一個明顯特徵。
2.在Java中,全部的繼承都是公有繼承,而沒有C++中的私有繼承和保護繼承.。
3.類繼承的格式:
Class 新類名 extends 已有類名
4.已有類名稱爲: 超類(superclass)、基類(bass class)或父類(parent class)
來自系統類庫
用戶自定義類
5.新類稱做:子類(subclass)、派生類(derived class)或孩子類(child class)
6.通常來講,子類比超類擁有的功能更加豐富
7.經過擴展超類定義子類時,僅須要指出子類與超類的不一樣之處。在子類中能夠增長域、增長方法或覆蓋超類的方法,但絕對不能刪除超類的任何域和方法。
8.關鍵字this有兩個用途:一是引用隱式參數,而是調用該類其餘的構造器。一樣,super是一個指示編譯器調用超類方法的特有關鍵字,它不是一個對象引用,不能將super賦給另外一個對象變量。Super關鍵字通常有兩個用途:以是調用超類的方法
(格式:super.方法名()),二是調用超類的構造器(格式:super())。
9.若子類構造器沒有顯示地調用超類地構造器,則將自動地調用超類默認構造器。若是超類只定義了帶參數地構造器,若子類構造器沒有顯示地調用超類地構造器,則Java編譯器將報告錯誤。
1)繼承層次:從一個超類擴展而來地類集合稱爲繼承層次。在繼承層次中,從某個類到其祖先地路徑被稱爲該類地繼承鏈。
Java不支持多繼承。
2)多態性
概念:多態性泛指在程序中同一個符號在不一樣地狀況下具備不一樣解釋地現象。
超類中定義地域或方法,被子類繼承以後,能夠具備不一樣地數據類型或表現出不一樣的行爲。
這使得在超類及其各個子類中同名的域或方法具備不一樣的語義。
超類中的的方法在子類中可方法重寫。
12.在Java中,不須要將方法聲明爲虛擬方法。動態綁定是默認的處理方式。若是不但願讓一個方法具備虛擬特徵,能夠將它標記爲final。
3)抽象類
觀察類的繼承層次結構,位於上層的類更具通用性,甚至可能更加抽象。從某種角度看,祖先類更加通用,人們只將它做爲派生其餘類的基類,而不做爲特定的實例類。
爲了提升程序清晰度,包含一個或多個抽象方法的類自己必須被聲明爲抽象類。除了抽象方法以外,抽象類還能夠包含具體數據和具體方法。
抽象方法充當着佔位的角色,它們的具體實如今子類中。擴展抽象類能夠有兩種選擇:一種是在子類中實現部分抽象方法,這樣就必須將子類也標記爲抽象類;另外一種是實現所有抽象方法,這樣子類就能夠不是抽象類。此外,類即便不含抽象方法,也能夠將類聲明爲抽象類。
抽象類不能被實例化,即不能建立對象,只能產生子類。能夠建立抽象類的對象變量,只是這個變量必須指向它的非抽象子類的對象。
4)動態綁定
概念:又稱爲運行時綁定。即程序在運行時會自動選擇調用哪一個方法。
調用對象方法的執行過程
首先,編譯器檢查對象的聲明類型和方法名,搜素相應類(Son)及其父類(father)的」方法表」,找出全部訪問屬性爲public的method方法。
接下來,編譯器檢查方法調用中提供的參數類型,找出一個徹底匹配的方法,這個過程稱爲重載解析。
若是方法時private、static、final修飾的,或者是構造器,那麼編譯器能準確地判斷應該調用哪一個方法,這稱爲靜態綁定。
程序運行時,若是子類son中定義了method()方法,則直接調用子類中地相應方法:若是子類son中沒有定義相應地方法,則到其父類中尋找method()方法。
動態綁定中每次調用方法都要進行搜素,時間開銷至關大。所以虛擬機預先爲每一個類建立了一個方法表,其中列了全部方法地簽名和實際調用地方法。
方法地名稱和參數列表稱爲方法地簽名。
例如,f(int)和f(String)是兩個具備相同名字,不一樣簽名的方法。若是在子類中定義了一個與超類簽名相同的方法,那麼子類中的這個方法就覆蓋了超類中的這個相同簽名的方法。不過,返回類型不是簽名的一部分,所以,在覆蓋方法時,必定要保證返回類型的兼容性。容許子類將覆蓋方法的返回類型定義爲原返回類型的子類型。
5)阻止繼承:final類和方法
不容許繼承地類稱爲final類,在類的定義中用final修飾符加以說明。
Final class Executive extends Manager
{ ........ }
類中的方法可定義爲final的。這時子類就不能覆蓋該方法。
若是一個類聲明爲final,屬於它的方法會被自動設爲final,但不包括域(若是域定義爲final,在對象構造之後,final域就不能再修改了)。
Private final int Max = 100;
String類是final類的一個例子,不能擴展該類。
6)強制類型轉換
若是要把一個超類對象賦給一個子類對象變量,就必須進行強制類型轉換。其格式爲:
子類 對象 = (子類) (超類對象)
Manager boss = (Manager) staff[0]; //ok!
類型轉換必須在繼承層次內進行;並且在超類轉換爲子類以前。應必須使用instanceof操做符進行繼承鏈檢查。
7)繼承小結
封裝、繼承和多態是面對對象的主要特徵。
繼承可提升代碼重用性,用extends關鍵字來實現。除構造方法以外,父類的全部方法和屬性都被子類繼承。
繼承創建了類與類間的關係,同時也是多態特徵的前提。
Java只支持單繼承,不直接支持多繼承(避免兩個父類出現同名方法的調用選擇困難)
Abstract修飾的抽象類不能被實例化爲對象,只能擴展子類:抽象類中的抽象方法充當着佔位的角色,它們的具體實如今子類中。
Final類不容許被繼承;類中final方法不容許被子類重寫。
8)受保護訪問
若是但願超類的某些方法或域容許被子類直接訪問,就須要在超類定義時,將這些方法或域聲明爲protected
Protected違背了OOP提倡的數據封裝原則。實際中要謹慎使用protected的訪問屬性。
若定義類時要限制類中某個方法的使用,就能夠將它聲明爲protected。這代表子類獲得信任,可使用這個方法,而其餘類則不行。
Java有4個訪問權限修飾符:
訪問修飾符:private protected public 默認
使用訪問修飾符的緣由:實現受限信息隱藏
信息隱藏目的:
對類中任何實現細節的更改不會影響使用該類的代碼
防止用戶意外刪除數據
易於使用類
訪問修飾符:
Public 該類或非該類都可訪問
Private 只有該類能夠訪問
protected 該類及其子類的成員能夠訪問,同一個包中的類也能夠訪問
默認 相同包中的類能夠訪問
位置 |
Private |
默認 |
protected |
Public |
同一個類 |
是 |
是 |
是 |
是 |
同一個包內的類 |
否 |
是 |
是 |
是 |
不一樣包內的子類 |
否 |
否 |
是 |
是 |
不一樣包而且不是子類 |
否 |
否 |
否 |
是 |
注:不寫訪問修飾符時默認爲friendly
(2)Object :全部類的超類
1.Object 類是Java中全部類的祖先——每個類都由它擴展而來。在不給出超類的狀況下,Java會自動把Object做爲要定義類的超類。
2.可使用類型爲Object 的變量指向任意類型的對象。但要對它們進行專門的操做都要進行類型轉換。
Object obj = new Employee(「Harry Hacker」35000);
Employee e = (Employee)obj;
3.在Java中,只有基本類型(pimitive types)不是對象,例如,數組、字符和布爾類型的值都不是對象。全部的數組類型,無論是對象數組仍是基本類型的數組都擴展於Object類。
1)equals方法
Object類中的equals方法用於測試某個對象是否同另外一個對象相等。它在Object類中的實現是判斷兩個對象是否具備相同的引用。若是兩個對象具備相同的引用,它們必定是相等的。
若是須要檢測兩個對象狀態的相等性,就須要在新類的定義中須要覆蓋equals方法。
定義子類的equals方法時,可調用超類的equals方法。
Super.equals(otherObject)
getClass方法將返回一個對象所屬的類。在檢測中,只有兩個對象屬於同一個類時,纔有可能相等。
2)hashCode方法
1.Object類中的hashCode方法導出某個對象的散列碼。散列碼時任意整數,表示對象的存儲地址。
2.兩個相等對象的散列碼相等。
3.字符串的散列值是由內容導出的,s與t的散列值是同樣的。字符串緩存sb與tb是不一樣的。
4.若是從新定義equals方法,就必須從新定義hashCode方法,以便用戶能夠將對象插入到散列表中。
5.hashCode方法應該返回一個整型數值(也能夠是負數),併合理地組合實例域的散列碼,以便可以讓各個不一樣的對象產生的散列碼更加均勻。
6.須要組合多個散列值時,能夠調用Objects.hash並提供多個參數。這個方法會對各個參數調用Objects.hashCode,並組合這些散列值。
7.Equals與hashCode的定義必須一致:若是x.equals(y)返回true,那麼x.hashCode()就必須與y.hashCode()具備相同的值。
8.若是存在數組類型的域,那麼可使用靜態的Ayyas.hashCode方法計算一個散列碼,這個散列碼由數組元素的散列碼組成。
9.java.lang.Object 1.0
int hashCode()
返回對象的散列碼。散列碼能夠是任意的整數,包括正數或負數。兩個想等的對象要求返回相等的散列碼。
10.java.lang.Objects 7
int hash(Object… objects)
返回一個散列碼,由提供的全部對象的散列碼組合而獲得。
static int hashCode(Object a)
若是a爲null返回0,不然返回a.hashCode()。
11.java.util.Arrays 1.2
static int hashCode(type[] a) 5.0
計算數組a的散列碼。組成這個數組的元素類型能夠是object,int,long,short,char,byte,boolean,float或double。
3)toString方法
1.Object類的toString方法返回一個表明該對象域值的字符串。
2.定義子類中的toString方法時,可先調用超類的toString方法。
super.toString( )
3.toString方法是很是重要的調試工具。標準類庫中,多數類定義了toString方法,以便用戶得到對象狀態的必要信息。
4.java.lang.Object 1.0
Class getClass()
返回包含對象信息的類對象。
boolean equals(Object otherObject)
比較兩個對象是否相等,若是兩個對象指向同一塊存儲區域,方法返回true;不然方法返回false。在自定義的類中,應該覆蓋這個方法。
String toString()
返回描述該對象的字符串。在自定義的類中,應該覆蓋這個方法。
5.java.lang.Class 1.0
String getName()
返回這個類的名字。
Class getSuperclass()
以Class對象的形式返回這個類的超類信息。
4)泛型數組列表
Java中,利用ArrayList類,可容許程序在運行時肯定數組的大小。
ArrayList是一個採用類型參數的泛型類。爲指定數組列表保存元素的對象類型,須要用一對尖括號將數組元素的對象類名括號起來加在後面。
ArrayList<Employee> staff = new ArrayList<Employee>();
沒有< >的ArrayList將被認爲是一個刪去了類型參數的「原始」類型。
數組列表的操做
ArrayList定義
ArrayList <T>對象=new ArrayList<T>();
例: ArrayList<Employee> staff = new ArrayList<Employee>(;
API: ArrayList 的構造器
ArrayList<T>()構造一 個 空數組列表
- ArrayList<T>(int initialCapacity)構造 -一個具備指定容量的空數組列表
b.添加新元素
API: boolean add(T obj)
把元素obj追加到數組列表的結尾
例: staff.add(new Empleoy(..);
c.統計個數
API: int size()
返回數組列表中當前元素個數
例: staff.size();
d.調整大小
API: void trimToSize()
把數組列表的存貯空間調整到當前大小
e.訪問
API: void set(int index, T obj)
將obj放入數組列表index位置,將覆蓋這個位置的原有內容。
API: T get(int index)
得到指定位置index的元素值
例: Employee harry = new Employee(..);
staff.set(1, harry);
Employeee = staff.get(1);
f.增長與刪除
API: boolean add(int index, T obj)
向後移動元素,在第n個位置插入obj
API: T remove(int index);
將第n個位置存放的對象刪除,並將後面的元素向前移動
例:
staff.add(i,harry);
Employee e = staff.remove(i);
5)對象包裝器與自動裝箱
全部基本數據類型都有着與之對應的預約義類,它們被稱爲對象包裝器(wrapper)。
如下前6個對象包裝器類都是從公共包裝器類Number繼承而來。
Integer
Long
F loat
Double
Short
Byte
Character
Void :
Boolean
對象包裝器類是不可變的,即一旦構造了包裝器,就不允許更改包裝在其中的值。且對象包裝器類仍是final,因此不能定義它們的子類。
使用對象包裝器的好處:
基本類型轉化爲對象
定義一些有用的基本方法(static方法)
在JavaSE5.0中,能夠自動的將基本數據類型轉換爲包裝器類的對象,將這種變換稱爲自動打包(autohoxine)。
ArrayList<Integer> list = new ArrayList<Integer> () ;
list. add(3);//翻譯成
li st. add(new Integer (3)) ;
相反地,當對一個包裝器類的對象進行賦值或算法。運算時,將會自動地拆包。
intn = list. get(i);
翻譯成
int n = list. get (i). intValue;
integer n =3;
n++;
打包和拆包是編譯器承認的。
6)參數數量可變的方法
在Java SE 5. 0之前的版本中,每一個Java方法都有固定數量的參數。然而,如今的版本提供了可以用可變的參數數量調用的方法(稱爲「可變參」方法)
用戶本身能夠定義可變參數的方法,並將參數指定爲任意類型,甚至是基本類型。
public PrintStream printf(String fmt, Object... args)
{
return format(fmt, args); }
System.out.print(%d %s」,n,「widgets");
實際的調用過程爲:
System.out.printf(%d %s",new Object[ ] {new Integer(n),「widgets"});
public static double max(double... values)
{
double largest = Double.MIN_ VALUE;
for (double v: values) if (v > largest) largest = V;
return largest;
}
double m = max(3.1, 40.4, -5);
編譯器將new double[] {3.1, 40.4, -5}傳遞給max方法。
7)枚舉類
要定義一個成績類,成績的範圍只能是A、B、C、D、E,接受其它類型的值都是違法的,應該如何定義呢?如何表示成績呢?整型、字符型?都不合適,由於爲沒有明確的類型對應,即便是字符型,超出了「A、B、C、D、E」範圍的字符程序須要特別處理,以便保證應用安全。
JavaSE5.0之後版本中提供了一種稱爲枚舉的類型定義方法。
聲明枚舉類
public enum Grade { A, B, C, D, E};
它包括一~個關鍵字enum, -一個新枚舉類型的名字
Grade以及爲Grade定義的一組值,這裏的值既非整型,亦非字符型。
枚舉類說明
枚舉類是一個類,它的隱含超類是java. lang. Enum。
枚舉值並非整數或其它類型,是被聲明的枚舉類的自身實例,例如A是Grade的-一個實例。
枚舉類不能有public修飾的構造函數,構造函數都是隱含pr ivate,編譯器自動處理。
枚舉值隱含都是由public、static、final修飾的,無須本身添加這些修飾符。
在比較兩個枚舉類型的值時,永遠不須要調用equals方法,直接使用」=="進行相等比較。
爲枚舉類增長構造函數
1.enum Size
2.
3.SMALL("S"), MEDIUM("MI"), LARGE("L"),
EXTRA_ LARGE("XL"); :
4.
5.private Size(String abbreviation)
6.
7.this. abbreviation = abbreviation;
8.
9.public String getAbbreviation(
10. {
return abbreviation; }
1l.
12.private String abbreviation;
13. }
8)反射
1.反射庫(reflection library)提供了一個很是豐富且精心設計的工具集,以便編寫可以動態操縱Java代碼的程序。特別是在設計或運行中添加新類時,可以快速地應用開發工具動態地查詢新添加類的能力。
2.可以分析類能力的程序稱爲反射(reflaction)。反射機制的功能及其強大,在下面能夠看到,反射機制能夠用來:
在運行中分析類的能力。
在運行中查看對象。
實現通用的數組操做代碼。
利用Method對象,這個對象很像C++中的函數指針。
9)Class類
1.在程序運行期間,Java運行時系統始終爲全部的對象維護一個被稱爲運行時的類型標識。這個信息跟蹤着每一個對象所屬的類。虛擬機利用運行時類型信息選擇相應的方法執行。然而,能夠經過專門的Java類訪問這些信息。保存這些信息的類被稱爲Class。Object類中的getClass()方法將會返回一個Class類型的實例。
2.一個Class對象將表示一個特定類的屬性。
3.能夠調用Class類的靜態方法forName得到類名對應的Class對象。若是類名保存在字符串中,並可在運行中改變,就可使用這個方法。固然,這個方法只有在className是類名或接口名時才能執行。不然,forName方法將拋出一個checkedexception(已檢查異常)。不管什麼時候使用這個方法,都應該提供一個異常處理器(exception handler)。·
4.一個Class對象實際上表示的是一個類型,而這個類型未必是一種類。
5.虛擬機爲每一個類型管理一個Class對象。所以,能夠利用==運算符實現兩個類對象比較的操做。
6.Class類的方法newInstance(),能夠用來快速地建立一個類的實例。newInstance方法調用默認的構造器(沒有參數的構造器)初始化新建立的對象。若是這個類沒有默認的構造器,就會拋出一個異常。
10)捕獲異常
1.異常有兩種類型:未檢查異常和已檢查異常。對於已檢查異常,編譯器將會檢查是否提供了處理器。未檢查異常編譯器不會查看是否爲這些錯誤提供了處理器。
2.java.lang.Class 1.0
static Class forName(String className)
返回描述類名爲className的Class對象。
Object newInstance()
返回這個類的一個新實例。
3.java.lang.reflect.Constructor 1.1
Object newInstance(Object[] args)
構造一個這個構造器所屬類的新實例。
參數:args 這是提供給構造器的參數。
4.java.lang.Throwable 1.0
void printStackTrace()
將Throwable對象和棧的軌跡輸出到標準錯誤流。
11)利用反射分析類的能力
1.在java.lang.reflact包中有三個類Field、Method和Constructor分別用於描述類的域、方法和構造器、這三個類都有一各叫作getName的方法,用來返回項目的名稱。Field類有一個getType方法,用來返回描述域所屬類型的Class對象。Method和Constructor類有可以報告參數類型的方法,它將返回一個整型數值,用不一樣的位開關描述public和static這樣修飾符使用情況。另外,還能夠利用java.lang.reflect包中的Modifier類的靜態方法分析getModifiers返回的整型數值。還能夠利用Modifier.toString方法將修飾符打印出來。
2.Class類中的getFields、getMethods和getConstructors方法將分別返回類提供的public域、方法和構造器數組,其中包括超類的公有成員。Class類的getDelareFields、getDeclareMethods和getDeclaredConstructors方法將分別返回類中聲明的所有域、方法和構造器,其中包括私有和受保護成員,但不包括超類的成員。
12)在運行時使用反射分析對象
1.查看對象域的關鍵方法是Field類中的get方法。
2.除非擁有訪問權限,不然Java安全機制只容許查看任意對象有哪些域,而不容許讀取他們的值。
3.反射機制的默認行爲受限於Java的訪問機制。然而,若是一個Java程序沒有受到安全管理器的控制,就能夠覆蓋訪問控制。
4.setAccessible方法是AccessibleObject類中的一個方法,它是Field、Method和Constructor類的公共超類。這個特性是爲調試、持久存儲和類似機制提供的。
5.調用Field的f.set(obj,value)能夠將obj對象的f域設置成新值。
6.使用Class的getDeclaredFields獲取全部的數據域,而後使用setAccessible將全部的域設置爲可訪問的。對於每一個域,得到了名字和值。
13)使用反射編寫泛型數組代碼
1.java.lang.reflect包中的Array類容許動態地建立數組。
2.能夠經過調用Array.getLength(a)得到數組的長度,也能夠經過Array類的靜態getLength方法的返回值獲得任意數組的長度。而要得到新數組元素類型,就須要進行如下工做:
1)首先得到數組的類對象。
2)確認它是一個數組。
3)使用Class類(只能定義表示數組的類對象)的getComponentType方法肯定數組對應的類型。
14)調用任意方法
1.在Method類中有一個invoke方法,它容許調用包裝在當前Method對象中的方法。invoke方法的簽名是:Object invoke(Object obj,Object... args)
,第一個參數是隱式參數,其他的對象提供了顯式參數。對於靜態方法,第一個參數能夠被忽略,便可以將它設置爲null。
2.如何獲得Method對象呢?固然,能夠經過調用getDeclareMethods方法,而後對返回的Method對象數組進行查找,直到發現想要的方法爲止。也能夠調用Class類中的getMethod方法獲得想要的方法。它與getField方法相似。getField方法根據表示域名的字符串,返回一個Field對象。然而,有可能存在若干個相同名字的方法,所以要格外當心,以確保可以準確地獲得想要的那個方法。有鑑於此,還必須提供想要的方法的參數類型。getMethod的簽名是:Method getMethod(String name,Class... parameterTypes)
。
3.若是在調用方法的時候提供了一個錯誤的參數,那麼invoke方法將會拋出一個異常。
4.nvoke的參數和返回值必須是Object類型的。這就意味着必須進行屢次的類型轉換。這樣作將會使編譯器錯過檢查代碼的機會。所以,等到測試階段纔會發現這些錯誤,找到並改正它們將會更加困難。不只如此,使用反射得到方法指針的代碼要比僅僅直接調用方法明顯慢一些。有鑑於此,建議僅在必要的時候才使用Method對象,而最好使用接口和內部類。特別要重申:建議Java開發者不要使用Method對象的回調功能。使用接口進行回調會使得代碼的執行速度更快,更易於維護。
5.java.lang.reflect.Method 1.1
public Object invoke(Object implicitParameter,Object[] explicitParamenters)
調用這個對象所描述的方法,傳遞給定參數,並返回方法的返回值。對於靜態方法,把null做爲隱式參數傳遞。在使用包裝器傳遞基本類型的值時,基本類型的返回值必須是未包裝的。
15)繼承設計的技巧
①將公共操做和域放在超類。
②不要使用受保護的域。
③使用繼承實現「 is- -a」關係。
④除非全部繼承的方法都有意義,不然就不要使用繼承。
⑤在覆蓋方法時,不要改變預期的行爲。
⑥使用多態,而非類型信息。
第二部分:實驗部分
一、實驗目的與要求
(1) 理解繼承的定義;
(2) 掌握子類的定義要求
(3) 掌握多態性的概念及用法;
(4) 掌握抽象類的定義及用途。
二、實驗內容和步驟
實驗1:導入第5章示例程序,測試並進行代碼註釋。
測試程序1:
在elipse IDE中編輯、調試、運行程序5-1 —5-3(教材152頁-153頁) ;
掌握子類的定義及用法;
結合程序運行結果,理解並總結OO風格程序構造特色,理解Employee和Manager類的關係子類的用途,並在代碼中添加註釋;
刪除程序中Manager類、ManagerTest類,背錄刪除類的程序代碼,在代碼錄入中理解父類與子類的關係和使用特色。
子類的定義及用法:一個父類能夠有多個子類,可是一個子類只能有一個父類。子類能夠經過extends關鍵字來繼承父類。
OO風格程序構造特色:封裝,繼承,多態,抽象
5-1程序代碼:
package inheritance; //package繼承 /** * 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 (構造一個管理對象) var boss = new Manager("Carl Cracker", 80000, 1987, 12, 15); boss.setBonus(5000); //使用setBonus方法 var staff = new Employee[3]; //定義一個包含3個僱員的數組 // fill the staff array with Manager and Employee objects (用 Manager 和Employee對象填充staff數組) 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 (打印出全部Employee對象的信息,輸出每一個人的薪水) for (Employee e : staff) System.out.println("name=" + e.getName() + ",salary=" + e.getSalary()); } }
5-2程序代碼:
package inheritance; //包繼承 import java.time.*; public class Employee { private String name; private double salary; private LocalDate hireDay; public Employee(String name, double salary, int year, int month, int day) { this.name = name; this.salary = salary; hireDay = LocalDate.of(year, month, day); } public String getName() //getName方法 { return name; } public double getSalary() //getSalary方法 { return salary; } public LocalDate getHireDay() //getHireDay方法 { return hireDay; } public void raiseSalary(double byPercent) { double raise = salary * byPercent / 100; salary += raise; } }
5-3程序代碼:
package inheritance; //包繼承 public class Manager extends Employee { private double bonus; /** * @param name the employee's name * @param salary the salary * @param year the hire year * @param month the hire month * @param day the hire day */ public Manager(String name, double salary, int year, int month, int day) //提供一個子類構造器 { super(name, salary, year, month, day); //調用超類Employee中含有n,s,year,month和day參數的構造器 bonus = 0; } public double getSalary() // Manager類中的 getSalary方法 { double baseSalary = super.getSalary(); //使用關鍵字super調用Employee類中的 getSalary方法 return baseSalary + bonus; } public void setBonus(double b) { bonus = b; } }
程序運行結果以下:
刪除程序中Manager類、ManagerTest類 的結果及修改:
測試程序2:
編輯、編譯、調試運行教材PersonTest程序(教材163頁-165頁);
掌握超類的定義及其使用要求;
掌握利用超類擴展子類的要求;
在程序中相關代碼處添加新知識的註釋;
刪除程序中Person類、PersonTest類,背錄刪除類的程序代碼,在代碼錄入中理解抽象類與子類的關係和使用特色。
5-4代碼:
package abstractClasses; /** * This program demonstrates abstract classes. * @version 1.01 2004-02-21 * @author Cay Horstmann */ public class PersonTest { public static void main(String[] args) { var people = new Person[2]; // fill the people array with Student and Employee objects //用Student和Employee對象填充people數組 people[0] = new Employee("Harry Hacker", 50000, 1989, 10, 1); people[1] = new Student("Maria Morris", "computer science"); // print out names and descriptions of all Person objects //打印出全部Person對象的名稱和描述 for (Person p : people) System.out.println(p.getName() + ", " + p.getDescription()); } }
5-5代碼:
package abstractClasses; public abstract class Person //定義了抽象超類Person { public abstract String getDescription(); //使用abstract關鍵字 private String name; public Person(String name) //Person類中保存着姓名和一個返回姓名的具體方法 { this.name = name; } public String getName() { return name; } }
5-6代碼:
package abstractClasses; import java.time.*; public class Employee extends Person //定義了子類Employee { private double salary; private LocalDate hireDay; public Employee(String name, double salary, int year, int month, int day) //提供一個子類構造器 { super(name); this.salary = salary; hireDay = LocalDate.of(year, month, day); } public double getSalary() //getSalary方法 { return salary; } public LocalDate getHireDay() // getHireDay方法 { return hireDay; } public String getDescription() //getDescription方法 { return String.format("an employee with a salary of $%.2f", salary); } public void raiseSalary(double byPercent) //raiseSalary方法 { double raise = salary * byPercent / 100; salary += raise; } }
5-7代碼:
package abstractClasses; public class Student extends Person //定義了子類Student { private String major; /** * @param name the student's name * @param major the student's major */ public Student(String name, String major) { // pass name to superclass constructor (將名稱傳遞給超類構造函數) super(name); this.major = major; } public String getDescription() //getDescription方法 { return "a student majoring in " + major; } }
代碼運行結果以下:
刪除程序中Person類、PersonTest類 的結果以及修改:
測試程序3:
編輯、編譯、調試運行教材程序5-8、5-9、5-10,結合程序運行結果理解程序(教材174頁-177頁);
掌握Object類的定義及用法;
在程序中相關代碼處添加新知識的註釋。
5-8程序代碼:
package equals; /** * This program demonstrates the equals method. * @version 1.12 2012-01-26 * @author Cay Horstmann */ public class EqualsTest //此程序實現了Employee類和Manager類的equals,hashCode,toString方法 { public static void main(String[] args) { var alice1 = new Employee("Alice Adams", 75000, 1987, 12, 15); var alice2 = alice1; var alice3 = new Employee("Alice Adams", 75000, 1987, 12, 15); var bob = new Employee("Bob Brandson", 50000, 1989, 10, 1); System.out.println("alice1 == alice2: " + (alice1 == alice2)); System.out.println("alice1 == alice3: " + (alice1 == alice3)); System.out.println("alice1.equals(alice3): " + alice1.equals(alice3)); System.out.println("alice1.equals(bob): " + alice1.equals(bob)); System.out.println("bob.toString(): " + bob); var carl = new Manager("Carl Cracker", 80000, 1987, 12, 15); var boss = new Manager("Carl Cracker", 80000, 1987, 12, 15); boss.setBonus(5000); System.out.println("boss.toString(): " + boss); System.out.println("carl.equals(boss): " + carl.equals(boss)); System.out.println("alice1.hashCode(): " + alice1.hashCode()); System.out.println("alice3.hashCode(): " + alice3.hashCode()); System.out.println("bob.hashCode(): " + bob.hashCode()); System.out.println("carl.hashCode(): " + carl.hashCode()); } }
5-9程序代碼:
package equals; import java.time.*; import java.util.Objects; public class Employee { private String name; private double salary; private LocalDate hireDay; public Employee(String name, double salary, int year, int month, int day) { this.name = name; this.salary = salary; hireDay = LocalDate.of(year, month, day); } public String getName() // getName方法 { return name; } public double getSalary() //getSalary方法 { return salary; } public LocalDate getHireDay() //getHireDay方法 { return hireDay; } public void raiseSalary(double byPercent) //raiseSalary方法 { double raise = salary * byPercent / 100; salary += raise; } public boolean equals(Object otherObject) { // a quick test to see if the objects are identical if (this == otherObject) return true; //檢測this與otherObject是否引用同一個對象 // must return false if the explicit parameter is null if (otherObject == null) return false; //檢測otherObject是否爲null,若是爲null,返回false // if the classes don't match, they can't be equal if (getClass() != otherObject.getClass()) return false; //比較this與otherObject是否屬於同一個類 // now we know otherObject is a non-null Employee var other = (Employee) otherObject; //強制類型轉換 // test whether the fields have identical values (測試字段是否具備相同的值) return Objects.equals(name, other.name) && salary == other.salary && Objects.equals(hireDay, other.hireDay); } public int hashCode() //hashCode方法 { return Objects.hash(name, salary, hireDay); } public String toString() //toString方法 { return getClass().getName() + "[name=" + name + ",salary=" + salary + ",hireDay=" + hireDay + "]"; } }
5-10程序代碼:
package equals; public class Manager extends Employee { private double bonus; public Manager(String name, double salary, int year, int month, int day) //提供一個子類構造器 { super(name, salary, year, month, day); bonus = 0; } public double getSalary() //getSalary方法 { double baseSalary = super.getSalary(); return baseSalary + bonus; } public void setBonus(double bonus) //使用setBonus方法 { this.bonus = bonus; } public boolean equals(Object otherObject) //equals方法 { if (!super.equals(otherObject)) return false; var other = (Manager) otherObject; //強制類型轉換 // super.equals checked that this and other belong to the same class (檢查這個和其餘都同屬於一個類) return bonus == other.bonus; } public int hashCode() //hashCode方法 { return java.util.Objects.hash(super.hashCode(), bonus); } public String toString() //Manager類中的toString方法 { return super.toString() + "[bonus=" + bonus + "]"; } }
代碼運行結果以下:
實驗2:編程練習
定義抽象類Shape:
屬性:不可變常量double PI,值爲3.14;
方法:public double getPerimeter();public double getArea())。
讓Rectangle與Circle繼承自Shape類。
編寫double sumAllArea方法輸出形狀數組中的面積和和double sumAllPerimeter方法輸出形狀數組中的周長和。
main方法中
1)輸入整型值n,而後創建n個不一樣的形狀。若是輸入rect,則再輸入長和寬。若是輸入cir,則再輸入半徑。
2) 而後輸出全部的形狀的周長之和,面積之和。並將全部的形狀信息以樣例的格式輸出。
3) 最後輸出每一個形狀的類型與父類型,使用相似shape.getClass()(得到類型),shape.getClass().getSuperclass()(得到父類型);
思考sumAllArea和sumAllPerimeter方法放在哪一個類中更合適?
輸入樣例:
輸出樣例:
程序代碼:
shape.java
package shape; public abstract class shape { double PI = 3.14; public abstract double getPerimeter(); public abstract double getArea(); }
Rectangle.java
package shape; public class Rectangle extends shape { private double width; private double length; public Rectangle(double w, double l) { this.width = w; this.length = l; } @Override public double getPerimeter() { // TODO Auto-generated method stub double Perimeter = (width+length)*2; return Perimeter; } @Override public double getArea() { // TODO Auto-generated method stub double Area = width*length; return Area; } @Override public String toString() { // TODO Auto-generated method stub return getClass().getName() + "[ width=" + width + "]" + "[length=" + length + "]"; } }
Circle.java
package shape; public class Circle extends shape { private double radius; public Circle(double r) { radius = r; } @Override public double getPerimeter() { // TODO Auto-generated method stub double Perimeter = 2*PI*radius; return Perimeter; } @Override public double getArea() { // TODO Auto-generated method stub double Area = PI*radius*radius; return Area; } @Override public String toString() { // TODO Auto-generated method stub return getClass().getName() + "[radius=" + radius + "]"; } }
shapeTest.java
package shape; import java.util.Scanner; public class shapeTest { public static void main(String[] args) { // TODO Auto-generated method stub Scanner in = new Scanner(System.in); String rect = "rect"; String cir = "cir"; System.out.println("請輸入形狀個數:"); int n = in.nextInt(); shape[] score = new shape[n]; for(int i = 0; i < n; i++) { System.out.println("(rect or cir):"); String input = in.next(); if(input.equals(rect)) { double length = in.nextDouble(); double width = in.nextDouble(); System.out.println("Rectangle["+"length:"+length+"width:"+width+"]"); score[i] = new Rectangle(width,length); } if(input.equals(cir)) { double radius = in.nextDouble(); System.out.println("Circle["+"radius:"+radius+"]"); score[i] = new Circle(radius); } } shapeTest c = new shapeTest(); System.out.println(c.sumAllPerimeter(score)); System.out.println(c.sumAllArea(score)); for(shape s:score) { System.out.println(s.getClass()+","+s.getClass().getSuperclass()); } in.close(); } private double sumAllArea(shape[] score) { // TODO Auto-generated method stub double sum = 0; for(int i = 0; i < score.length; i++) sum+= score[i].getArea(); return sum; } private double sumAllPerimeter(shape[] score) { // TODO Auto-generated method stub double sum = 0; for(int i = 0; i < score.length; i++) sum+= score[i].getPerimeter(); return sum; } }
運行結果:
3. 實驗總結
本次學習理解了Java程序設計中類與對象的關係,理解OO程序設計的特徵:繼承和多態,並學會採用繼承定義類設計程序,掌握利用了父類定義子類的語法規則及對象使用要求。在完成實驗過程當中理解了繼承的定義,掌握子類的定義要求,多態性的概念及用法,抽象類的定義及用途。本章知識比較多也比較重要,仍須要多多增強鞏固,繼續努力。