張雲飛 201771010143 《面對物件程式設計(java)》第十週學習總結
實驗十 泛型程式設計技術
實驗時間2018-11-1
1、實驗目的與要求
(1) 理解泛型概念;
(2) 掌握泛型類的定義與使用;
(3) 掌握泛型方法的宣告與使用;
(4) 掌握泛型介面的定義與實現;
(5)瞭解泛型程式設計,理解其用途。
2、實驗內容和步驟
實驗1: 匯入第8章示例程式,測試程式並進行程式碼註釋。
測試程式1:
l 編輯、除錯、執行教材311、312頁 程式碼,結合程式執行結果理解程式;
l 在泛型類定義及使用程式碼處添加註釋;
l 掌握泛型類的定義及使用。
import ArrayAlg;
/**
* @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
{
/**
* 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];
String 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);
}
}
測試程式2:
編輯、除錯執行教材315頁 PairTest2,結合程式執行結果理解程式;
在泛型程式設計程式碼處新增相關注釋;
掌握泛型方法、泛型變數限定的定義及用途。
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;
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);
}
}
測試程式3:
用除錯執行教材335頁 PairTest3,結合程式執行結果理解程式;
瞭解萬用字元型別的定義及用途。
/**
* @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;
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);
PairAlg.swapHelper(result); // OK--swapHelper captures wildcard type
}
// Can't write public static <T super manager> ...
}
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:實驗九程式設計題總結
實驗九程式設計練習1總結
程式總體結構說明:計算器我當時才看到題目就是首先想到的是使用math.random來生成隨機數以此來生成算數式,然後設定四個函式進行呼叫。只不過在隨機生成加減乘除的時候使用的語句自己也覺得過於複雜了一點,依舊是使用了math.random來輸出一個隨機數,然後對其乘以10後取整,以case1234來分別呼叫加減乘除四個函式,並同時定義了計數器cnt,在一輪勻速成功後,cnt++,並且cnt<10.
模組說明:
目前程式設計存在的困難與問題:對於迴圈的利用基本熟練,但是寫出來的語句有時候還是太過於冗長繁瑣,還需要多多練習。
package 人員身份證;
import java.util.*;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
public class test{
public static void main (String[] args)
{
Scanner in=new Scanner(System.in);
PrintWriter output = null;
try {
output = new PrintWriter("ss.txt");
} catch (Exception e) {
//e.printStackTrace();
}
int score;
int a=(int)Math.round(Math.random()*100);
int b=(int)Math.round(Math.random()*100);
int Input = in.nextInt();
int i=(int)Math.round(Math.random()*10);
while(i<5)
{
for (int cnt=0;cnt<10;cnt++)
{
switch(i) {
case'1':
plus(a,b);
break;
case'2':
minus(a,b);
break;
case'3':
multiple(a,b);
break;
case'4':
division(a,b);
break;
}
}
break;
}
}
public static void plus(int a,int b)
{
Scanner in=new Scanner(System.in);
int out=a+b;
boolean correction;
int Input=in.nextInt();
System.out.println("請輸入答案"+(a)+(b));
if(Input==a+b) {
correction=true;
System.out.println("答案正確");
}
else
{
System.out.println("答案錯誤");
}
}
public static void minus(int a,int b)
{
Scanner in=new Scanner(System.in);
boolean correction;
int Input=in.nextInt();
System.out.println("請輸入答案"+a+"-"+b);
if(Input==a-b) {
correction=true;
System.out.println("答案正確");
}
else
{
System.out.println("答案錯誤");
}
}
public static void multiple(int a,int b)
{
Scanner in=new Scanner(System.in);
boolean correction;
int Input=in.nextInt();
System.out.println("請輸入答案"+a+"*"+b);
if(Input==a*b) {
correction=true;
System.out.println("答案正確");
}
else
{
System.out.println("答案錯誤");
}
}
public static void division(int a,int b)
{
Scanner in=new Scanner(System.in);
boolean correction;
int Input=in.nextInt();
System.out.println("請輸入答案"+a+"/"+b);
if(Input==a/b) {
correction=true;
System.out.println("答案正確");
}
else
{
System.out.println("答案錯誤");
}
}
}
程式總體結構說明:在上面的基礎上加入了異常除錯語句。
模組說明:函式:plus,minus,multiple,division
異常除錯語句:PrintWriter output = null;
try {
output = new PrintWriter("ss.txt");
} catch (Exception e) {
//e.printStackTrace();
}
目前程式設計存在的困難與問題:接著後來老師講了異常處理,於是在程式中又加入了異常除錯的語句。一開始並不是很理解異常除錯語句的作用,後來看了書大概理解了ava把程式執行時可能遇到的錯誤分為兩類:非致命異常:通過某種修正後程序還能繼續執行。這類錯誤叫作異常。如:檔案不存在、無效的陣列下標、空引用、網路斷開、印表機離線、磁碟滿等。 Java中提供了一種獨特的處理異常的機制,通過異常來處理程式設計中出現的錯誤。致命異常:程式遇到了非常嚴重的不正常狀態,不能簡單恢復執行,是致命性錯誤。如:記憶體耗盡、系統內部錯誤等。這種錯誤程式本身無法解決。異常除錯,運用還不是很熟練。
程式設計練習2:採用泛型程式設計技術改進實驗九程式設計練習2,使之可處理實數四則運算,其他要求不變。
package 異常;
public class Demo<T> {
private T a;
private T b;
public Demo() {
a = null;
b = null;
}
public Demo(T a, T b) {
this.a = a;
this.b = b;
}
public int demo1(int a, int b) {
return a + b;
}
public int demo2(int a, int b) {
return a - b;
}
public int demo3(int a, int b) {
return a * b;
}
public int demo4(int a, int b) {
return a / b;
}
}
Demo
package 異常;
import java.io.PrintWriter;
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
@SuppressWarnings("resource")
Scanner in = new Scanner(System.in);
Demo demo=new Demo();
PrintWriter output = null;
try {
output = new PrintWriter("test.txt");
} catch (Exception e) {
e.printStackTrace();
}
int sum = 0;
for (int i = 0; i < 10; i++) {
int a = (int) Math.round(Math.random() * 100);
int b = (int) Math.round(Math.random() * 100);
int c = (int) Math.round(Math.random() * 3);
switch (c) {
case 0:
System.out.println(a + "+" + b + "=");
int d0 = in.nextInt();
output.println(a + "+" + b + "=" + d0);
if (d0 == demo.demo1(a, b)) {
sum += 10;
System.out.println("恭喜答案正確");
} else {
System.out.println("抱歉,答案錯誤");
}
break;
case 1:
while (a < b) {
int x = a;
a = b;
b = x;
}
System.out.println(a + "-" + b + "=");
int d1 = in.nextInt();
output.println(a + "-" + b + "=" + d1);
if (d1 == demo.demo2(a, b)) {
sum += 10;
System.out.println("恭喜答案正確");
} else {
System.out.println("抱歉,答案錯誤");
}
break;
case 2:
System.out.println(a + "*" + b + "=");
int d2 = in.nextInt();
output.println(a + "*" + b + "=" + d2);
if (d2 == demo.demo3(a, b)) {
sum += 10;
System.out.println("恭喜答案正確");
} else {
System.out.println("抱歉,答案錯誤");
}
break;
case 3:
while (b == 0 || a % b != 0) {
a = (int) Math.round(Math.random() * 100);
b = (int) Math.round(Math.random() * 100);
}
System.out.println(a + "/" + b + "=");
int d3 = in.nextInt();
output.println(a + "/" + b + "=" + d3);
if (d3 == demo.demo4(a, b)) {
sum += 10;
System.out.println("恭喜答案正確");
} else {
System.out.println("抱歉,答案錯誤");
}
break;
}
}
System.out.println("你的得分為" + sum);
output.println("你的得分為" + sum);
output.close();
}
}
本週學習總結:型別擦除指的是通過型別引數合併,將泛型型別例項關聯到同一份位元組碼上。編譯器只為泛型型別生成一份位元組碼,並將其例項關聯到這份位元組碼上,因此泛型型別中的靜態變數是所有例項共享的。此外,需要注意的是,一個static方法,無法訪問泛型類的型別引數,因為類還沒有例項化,所以,若static方法需要使用泛型能力,必須使其成為泛型方法。型別擦除的關鍵在於從泛型型別中清除型別引數的相關資訊,並且再必要的時候新增型別檢查和型別轉換的方法。在使用泛型時,任何具體的型別都被擦除,唯一知道的是你在使用一個物件。比如:List<String>和List<Integer>在執行事實上是相同的型別。他們都被擦除成他們的原生型別,即List。因為編譯的時候會有型別擦除,所以不能通過同一個泛型類的例項來區分方法,如下面的例子編譯時會出錯,因為型別擦除後,兩個方法都是List型別的引數,因此並不能根據泛型類的型別來區分方法。
泛型程式設計(Generic programming)意味著編寫的程式碼可以被很多不同的型別的物件所重用。
使用泛型機制編寫的程式程式碼要比那些雜亂地使用Object變數然後再進行強制型別轉換的程式碼具有更好的安全性和可讀性。泛型對於集合類特別有用,像ArrayList就是一個無處不在的集合類。
泛型提供了一個很好的方案:
型別引數(type parameters)ArrayList類有一個型別引數來指示元素的型別
ArrayList<String> files=new ArrayList<>();
1
這樣的程式碼具有很好地可讀性,人們一下就能知道這個ArrayList中的元素是什麼型別的了。
這也正是型別引數的魅力所在,除此之外還有安全性。
get的時候不需要進行強制型別轉換編譯器就能知道返回值型別為String