劉志梅 2017710101152《面向物件程式設計(java)》 第十週學習總結
實驗十 泛型程式設計技術
實驗時間 2018-11-1
1、實驗目的與要求
(1)泛型程式設計:意味著編寫的程式碼可以被很多不同型別的物件所重用。(ArrayList類可以聚集任何型別的物件)
如果在其它地方,若將get的結果強制型別轉換為String型別,就會產生一個錯誤;泛型類提供了更好地解決方案:型別引數(型別引數的魅力在於使得程式具有更好地可讀性和安全性)。
(2) 定義簡單泛型類:一個泛型類就是具有一個或多個型別變數的類(泛型類可以有多個型別變數)。
類定義中的型別變數指定方法的返回型別以及域和區域性變數的型別。
(3) 泛型方法
一個型別變數或萬用字元可以有多個限定;限定型別用“&”分隔,而逗號用來分隔型別變數;在java繼承中,可以根據需要擁有多個介面超型別,但限定中至多有一個類。
(4) 虛擬機器沒有泛型類行物件--所有物件都屬於普通類;無論何時定義一個泛型型別,都自動提供了一個相應的原始型別(原始型別的名字就是刪去型別引數後的泛型型別名)。
原始型別用第一個限定的型別變數來替換,如果沒有給定限定就用Object替換。
當程式呼叫泛型方法時,如果擦除返回型別,編譯器插入強制型別轉換;當存取一個泛型域時也要插入強制型別轉換。
(5)型別擦除也會出現在泛型方法中;一個日期區間是一對
有關java泛型類轉換的事實:虛擬機器中沒有泛型,只有普通的類和方法;所有的型別引數都用它們的限定型別替換;橋方法被合成來保持多型;為保持型別安全性,必要時插入強制型別轉換。
設計java泛型型別時,主要目標是允許泛型程式碼和遺留程式碼之間能夠相互操作;在查看了警告之後,可以利用註解使之消失;註釋必須放在生成這個警告的程式碼所在的方法之前。
大多數限制都是由型別擦除引起的;不能用型別引數代替基本型別;虛擬機器中的物件總有一個非泛型型別,因此,所有的型別查詢只產生原始型別;java不支援泛型型別的陣列。
不能使用像
就像不能例項化一個泛型例項一樣,也不能例項化陣列;如果陣列僅僅作為一個類的私有例項域,就可以將這個陣列宣告為Object[],並且在獲取元素時進行型別轉換。
不能在靜態域或方法中引用型別變數;既不能丟擲也不能捕獲泛型類物件(實際上,甚至泛型類擴充套件Throwable都是不合法的,不過,在異常規範中使用型別變數是允許的);java處理異常的一個基本原則是,必須為所有受查異常提供一個處理器。
通過使用泛型類、擦除和@SuppressWarnings註解,就能消除java型別系統的部分基本限制。
當泛型型別被擦除時,無法建立引發衝突的條件;泛型規範說明還提到另外一個原則:“要想支援擦除的轉換,就需要強行限制一個類或型別變數不能同時成為兩個介面型別的子類,而這兩個介面是同一介面的不同引數化”。
(6)永遠可以將引數化型別轉換為一個原始型別;泛型型別可以擴充套件或實現其他的泛型類。
(7)萬用字元型別中,允許型別引數變化;萬用字元限定於型別變數限定十分類似,但是,還有一個附加的能力,即可以指定一個超型別限定,可以為方法提供引數,但不能使用返回值;子型別限定的另一個常見的用法是作為一個函式式介面的引數型別。
還可以使用無限定的萬用字元,例如Pair<?>;Pair<?>和Pair本質的不同在於:可以用任意的Object物件呼叫原始Pair類的setObject方法;萬用字元不是型別變數,因此,不能在編寫程式碼中使用“?”作為一種型別。
萬用字元捕獲只有在許多限制的情況下才是合法的;編譯器必須能夠確信萬用字元表達的是單個、確定的型別。
(8)反射允許你在執行時分析任意的物件(如果物件是泛型類的例項,關於泛型型別引數則得不到太多資訊,因為他們會被擦除)。
有時,匹配泛型方法中的Class<T>引數的型別變數很有實用價值;java泛型的卓越特性之一是在虛擬機器中泛型型別的擦除;擦除的類仍然保留一些泛型祖先的微弱記憶。
2、實驗內容和步驟
實驗1: 匯入第8章示例程式,測試程式並進行程式碼註釋。
測試程式1:
l 編輯、除錯、執行教材311、312頁 程式碼,結合程式執行結果理解程式;
l 在泛型類定義及使用程式碼處添加註釋;
l 掌握泛型類的定義及使用。
/** * @version 1.01 2012-01-26 * @author Cay Horstmann */ public class PairTest1 { public static void main(String[] args) { String[] words = { "Mary", "had", "a", "little", "lamb" }; Pair<String> mm = ArrayAlg.minmax(words); System.out.println("min = " + mm.getFirst()); System.out.println("max = " + mm.getSecond()); } } class ArrayAlg //類ArrayAlg { /** * Gets the minimum and maximum of an array of strings. * @param a an array of strings * @return a pair with the min and max value, or null if a is null or empty */ public static Pair<String> minmax(String[] a) { if (a == null || a.length == 0) return null; String min = a[0];//字串min=[0] String max = a[0];//字串max=[0] for (int i = 1; i < a.length; i++) { if (min.compareTo(a[i]) > 0) min = a[i]; if (max.compareTo(a[i]) < 0) max = a[i]; } return new Pair<>(min, max);//返回新的Pair } }
測試程式2:
l 編輯、除錯執行教材315頁 PairTest2,結合程式執行結果理解程式;
l 在泛型程式設計程式碼處新增相關注釋;
l 掌握泛型方法、泛型變數限定的定義及用途。
import java.time.*; /** * @version 1.02 2015-06-21 * @author Cay Horstmann */ public class PairTest2 { public static void main(String[] args) { LocalDate[] birthdays = { LocalDate.of(1906, 12, 9), // G. Hopper LocalDate.of(1815, 12, 10), // A. Lovelace LocalDate.of(1903, 12, 3), // J. von Neumann LocalDate.of(1910, 6, 22), // K. Zuse }; Pair<LocalDate> mm = ArrayAlg.minmax(birthdays); System.out.println("min = " + mm.getFirst()); System.out.println("max = " + mm.getSecond()); } } class ArrayAlg { /** Gets the minimum and maximum of an array of objects of type T. @param a an array of objects of type T @return a pair with the min and max value, or null if a is null or empty */ public static <T extends Comparable> Pair<T> minmax(T[] a) { if (a == null || a.length == 0) return null;//如果(a==null ||長度==0)返回null值 T min = a[0]; T max = a[0]; for (int i = 1; i < a.length; i++) { if (min.compareTo(a[i]) > 0) min = a[i]; if (max.compareTo(a[i]) < 0) max = a[i]; } return new Pair<>(min, max);//返回新Pair<最小,最大> } }
測試程式3:
l 用除錯執行教材335頁 PairTest3,結合程式執行結果理解程式;
l 瞭解萬用字元型別的定義及用途。
/** * @version 1.01 2012-01-26 * @author Cay Horstmann */ public class PairTest3 { public static void main(String[] args) { Manager ceo = new Manager("Gus Greedy", 800000, 2003, 12, 15); Manager cfo = new Manager("Sid Sneaky", 600000, 2003, 12, 15); Pair<Manager> buddies = new Pair<>(ceo, cfo); printBuddies(buddies); ceo.setBonus(1000000); cfo.setBonus(500000); Manager[] managers = { ceo, cfo }; Pair<Employee> result = new Pair<>(); minmaxBonus(managers, result); System.out.println("first: " + result.getFirst().getName() + ", second: " + result.getSecond().getName()); maxminBonus(managers, result); System.out.println("first: " + result.getFirst().getName() + ", second: " + result.getSecond().getName()); } public static void printBuddies(Pair<? extends Employee> p) { Employee first = p.getFirst(); Employee second = p.getSecond(); System.out.println(first.getName() + " and " + second.getName() + " are buddies."); } public static void minmaxBonus(Manager[] a, Pair<? super Manager> result) { if (a.length == 0) return;//如果(一個.長度==0)返回; Manager min = a[0]; Manager max = a[0]; for (int i = 1; i < a.length; i++) { if (min.getBonus() > a[i].getBonus()) min = a[i]; if (max.getBonus() < a[i].getBonus()) max = a[i]; } result.setFirst(min); result.setSecond(max); } public static void maxminBonus(Manager[] a, Pair<? super Manager> result) { minmaxBonus(a, result);// minmaxBonus(結果) PairAlg.swapHelper(result); // OK--swapHelper captures wildcard type } // Can't write public static <T super manager> ...不能寫公共靜態T超級經理 } class PairAlg { public static boolean hasNulls(Pair<?> p) { return p.getFirst() == null || p.getSecond() == null; } public static void swap(Pair<?> p) { swapHelper(p); } public static <T> void swapHelper(Pair<T> p) { T t = p.getFirst(); p.setFirst(p.getSecond()); p.setSecond(t); } }
實驗2:程式設計練習:
程式設計練習1:實驗九程式設計題總結
l 實驗九程式設計練習1總結(從程式總體結構說明、模組說明,目前程式設計存在的困難與問題三個方面闡述)。
main類:將人員資訊匯入;編輯查詢方法;分五個case進行
package shen; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Scanner; public class Main { /** * 檔案讀取模組 利用ArrayList構造studentlist存放檔案內容; 建立檔案字元流,分類讀取檔案內容;try/catch語句捕獲異常 */ private static ArrayList<Student> studentlist; public static void main(String[] args) { studentlist = new ArrayList<>(); Scanner scanner = new Scanner(System.in); File file = new File("C:\\Users\\ASUS\\Desktop\\新建資料夾\\身份證號.txt"); try { FileInputStream fis = new FileInputStream(file); BufferedReader in = new BufferedReader(new InputStreamReader(fis)); String temp = null; while ((temp = in.readLine()) != null) { Scanner linescanner = new Scanner(temp); linescanner.useDelimiter(" "); String name = linescanner.next(); String number = linescanner.next(); String sex = linescanner.next(); String age = linescanner.next(); String province = linescanner.nextLine(); Student student = new Student(); student.setName(name); student.setnumber(number); student.setsex(sex); int a = Integer.parseInt(age); student.setage(a); student.setprovince(province); studentlist.add(student); } } catch (FileNotFoundException e) { System.out.println("學生資訊檔案找不到"); e.printStackTrace(); // 加入的捕獲異常程式碼 } catch (IOException e) { System.out.println("學生資訊檔案讀取錯誤"); e.printStackTrace(); // 加入的捕獲異常程式碼 } /* * 1.根據實驗要求,選擇具體操作的模組,用switch語句具體的操作 */ boolean isTrue = true; while (isTrue) { System.out.println("選擇你的操作,輸入正確格式的選項"); System.out.println("A.字典排序"); System.out.println("B.輸出年齡最大和年齡最小的人"); System.out.println("C.尋找老鄉"); System.out.println("D.尋找年齡相近的人"); System.out.println("F.退出"); String m = scanner.next(); switch (m) { case "A": Collections.sort(studentlist); System.out.println(studentlist.toString()); break; case "B": int max = 0, min = 100; int j, k1 = 0, k2 = 0; for (int i = 1; i < studentlist.size(); i++) { j = studentlist.get(i).getage(); if (j > max) { max = j; k1 = i; } if (j < min) { min = j; k2 = i; } } System.out.println("年齡最大:" + studentlist.get(k1)); System.out.println("年齡最小:" + studentlist.get(k2)); break; case "C": System.out.println("老家?"); String find = scanner.next(); String place = find.substring(0, 3); for (int i = 0; i < studentlist.size(); i++) { if (studentlist.get(i).getprovince().substring(1, 4).equals(place)) System.out.println("老鄉" + studentlist.get(i)); } break; case "D": System.out.println("年齡:"); int yourage = scanner.nextInt(); int near = agenear(yourage); int value = yourage - studentlist.get(near).getage(); System.out.println("" + studentlist.get(near)); break; case "F": isTrue = false; System.out.println("退出程式"); break; default: System.out.println("輸入有誤"); } } } /* * 對年齡資料進行處理 */ public static int agenear(int age) { int j = 0, min = 53, value = 0, k = 0; for (int i = 0; i < studentlist.size(); i++) { value = studentlist.get(i).getage() - age; if (value < 0) value = -value; if (value < min) { min = value; k = i; } } return k; } }
package shen; /* * 分類返回具體資料 *利用介面技術比較name的大小 *用toString方法返回資料 */ public class Student implements Comparable<Student> { private String name; private String number; private String sex; private int age; private String province; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getnumber() { return number; } public void setnumber(String number) { this.number = number; } public String getsex() { return sex; } public void setsex(String sex) { this.sex = sex; } public int getage() { return age; } public void setage(int age) { // int a = Integer.parseInt(age); this.age = age; } public String getprovince() { return province; } public void setprovince(String province) { this.province = province; } public int compareTo(Student o) { return this.name.compareTo(o.getName()); } public String toString() { //用toString返回 return name + "\t" + sex + "\t" + age + "\t" + number + "\t" + province + "\n"; } }
l 實驗九程式設計練習2總結(從程式總體結構說明、模組說明,目前程式設計存在的困難與問題三個方面闡述)。
判斷程式碼是否正確;檔案的讀取;及四則運算。
package demo; import java.io.FileNotFoundException; import java.io.PrintWriter; import java.util.Random; import java.util.Scanner; public class demo { public static void main(String[] args) { /** *檔案輸出模組 *1.呼叫建構函式counter *2.建立檔案字元流,將out中的內容設為空(null) *3.將out結果輸出到test.txt中 *4.try/catch模組捕獲異常 */ Scanner in = new Scanner(System.in); yunsuan counter = new yunsuan(); PrintWriter out = null; try { out = new PrintWriter("text.txt"); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } /** *四則運算生成模組 *1.定義一個int型sum,計算成績,並說明生成的運算型別 *2.for語句,將{}內的內容迴圈10次,從而生成10道題目 *3.隨機生成int型a與b,範圍在0到100以內;生成int型m,範圍為1,2,3,4 *4.利用switch語句,根據生成m的值,隨機生成加減乘除四則運算 *5.將迴圈結果輸出到test.txt中 */ int sum = 0; System.out.println("隨機生成的四則運算型別"); System.out.println("型別1:除法"); System.out.println("型別2:乘法"); System.out.println("型別3:加法"); System.out.println("型別4:減法"); for (int i = 1; i <= 10; i++) { int a = (int) Math.round(Math.random() * 100); int b = (int) Math.round(Math.random() * 100); int m; Random rand = new Random(); m = (int) rand.nextInt(4) + 1; System.out.println("隨機生成的四則運算型別:"+m); switch (m) { case 1: System.out.println(i + ": " + a + "/" + b + "="); while (b == 0) { b = (int) Math.round(Math.random() * 100); } double c0 = in.nextDouble(); out.println(a + "/" + b + "=" + c0); if (c0 == counter.division(a, b)) { sum += 10; System.out.println("right!"); } else { System.out.println("error!"); } break; case 2: System.out.println(i + ": " + a + "*" + b + "="); int c = in.nextInt(); out.println(a + "*" + b + "=" + c); if (c == counter.multiplication(a, b)) { sum += 10; System.out.println("right!"); } else { System.out.println("error!"); } break; case 3: System.out.println(i + ": " + a + "+" + b + "="); int c1 = in.nextInt(); out.println(a + "+" + b + "=" + c1); if (c1 == counter.add(a, b)) { sum += 10; System.out.println("right!"); } else { System.out.println("error!"); } break; case 4: System.out.println(i + ": " + a + "-" + b + "="); int c2 = in.nextInt(); out.println(a + "-" + b + "=" + c2); if (c2 == counter.reduce(a, b)) { sum += 10; System.out.println("right!"); } else { System.out.println("error!"); } break; } } System.out.println("成績" + sum); out.println("成績:" + sum); out.close(); } }
package demo; public class yunsuan { private int a; private int b; public int add(int a,int b) { return a+b; } public int reduce(int a,int b) { return a-b; } public int multiplication(int a,int b) { return a*b; } public int division(int a,int b) { if(b!=0) return a/b; else return 0; } }
程式設計練習2:採用泛型程式設計技術改進實驗九程式設計練習2,使之可處理實數四則運算,其他要求不變。
package demo; import java.io.FileNotFoundException; import java.io.PrintWriter; import java.util.Random; import java.util.Scanner; public class demo { public static void main(String[] args) { /** *檔案輸出模組 *1.呼叫建構函式counter *2.建立檔案字元流,將out中的內容設為空(null) *3.將out結果輸出到test.txt中 *4.try/catch模組捕獲異常 */ Scanner in = new Scanner(System.in); yunsuan counter = new yunsuan(); PrintWriter out = null; try { out = new PrintWriter("test.txt"); } catch (FileNotFoundException e) { System.out.println("資料夾輸出失敗"); e.printStackTrace(); } /** *四則運算生成模組 *1.定義一個int型sum,計算成績,並說明生成的運算型別 *2.for語句,將{}內的內容迴圈10次,從而生成10道題目 *3.隨機生成int型a與b,範圍在0到100以內;生成int型m,範圍為1,2,3,4 *4.利用switch語句,根據生成m的值,隨機生成加減乘除四則運算 *5.將迴圈結果輸出到test.txt中 */ int sum = 0; System.out.println("隨機生成的四則運算型別"); System.out.println("型別1:除法"); System.out.println("型別2:乘法"); System.out.println("型別3:加法"); System.out.println("型別4:減法"); for (int i = 1; i <= 10; i++) { int a = (int) Math.round(Math.random() * 100); int b = (int) Math.round(Math.random() * 100); int m; Random rand = new Random(); m = (int) rand.nextInt(4) + 1; System.out.println("隨機生成的四則運算型別:" + m); switch (m) { case 1: a = b + (int) Math.round(Math.random() * 100); while(b == 0){ b = (int) Math.round(Math.random() * 100); } while(a % b != 0){ a = (int) Math.round(Math.random() * 100); } //若生成的除法式子必須能整除,且滿足分母為0的條件,則a一定要大於b,且a模b的結果要為0。 System.out.println(i + ": " + a + "/" + b + "="); int c0 = in.nextInt(); out.println(a + "/" + b + "=" + c0); if (c0 == counter.division(a, b)) { sum += 10; System.out.println("right!"); } else { System.out.println("error!"); } break; case 2: System.out.println(i + ": " + a + "*" + b + "="); int c = in.nextInt(); out.println(a + "*" + b + "=" + c); if (c == counter.multiplication(a, b)) { sum += 10; System.out.println("right!"); } else { System.out.println("error!"); } break; case 3: System.out.println(i + ": " + a + "+" + b + "="); int c1 = in.nextInt(); out.println(a + "+" + b + "=" + c1); if (c1 == counter.add(a, b)) { sum += 10; System.out.println("right!"); } else { System.out.println("error!"); } break; case 4: while (a < b) { b = (int) Math.round(Math.random() * 100); } //因為不能產生運算結果為負數的減法式子,所以a一定要大於b。若a<b,則重新生成b。 System.out.println(i + ": " + a + "-" + b + "="); int c2 = in.nextInt(); out.println(a + "-" + b + "=" + c2); if (c2 == counter.reduce(a, b)) { sum += 10; System.out.println("right!"); } else { System.out.println("error!"); } break; } } System.out.println("成績" + sum); out.println("成績:" + sum); out.close(); } }
package demo; public class yunsuan<T> { private T a; private T b; public yunsuan() { a = null; b = null; } public yunsuan(T a, T b) { this.a = a; this.b = b; } public int add(int a,int b) { return a + b; } public int reduce(int a, int b) { return a - b; } public int multiplication(int a, int b) { return a * b; } public int division(int a, int b) { if (b != 0 && a%b==0) return a / b; else return 0; } }
實驗總結:通過本週實驗及課本的內容,學習了泛型的概念與運用,知道了泛型的具體定義、以及它的使用;最後的程式設計實驗是在之前的實驗上進行修改、新增本章學習的泛型語句然後實現的,實驗不夠熟練,還需要多多練習。