201521123091 《Java程序設計》第8周學習總結


Java 第八周總結

第八周的作業。

目錄
1.本章學習總結
2.Java Q&A
3.碼雲上代碼提交記錄及PTA實驗總結


1.本章學習總結

1.1 以你喜歡的方式(思維導圖或其他)歸納總結集合與泛型相關內容。
  上次我講了容器,這次就講泛型。
  容器類,可以持有大量對象。如果我們要存儲不同類型的對象,則可以讓容器去持有Object類型的對象,即全部向上轉型至根類。但是我們通常只會使用容器來存儲一種類型的對象,這時就需要我們指定容器來持有什么類型的對象,然后在編譯階段的時候就能保證不會持有除指定類型外的其他類型的對象。
  Java SE5引入泛型,泛型實現了參數化類型,允許我們用一對尖括號將類型參數括住,然后放在類名后面。然后可以再用實際的類型去替換此類型參數。
  這邊要注意的還有,就是容器里面可以存放該類型,或者是該類型的子類,所以多態和泛型並不起沖突。我可以向持有父類的容器發送消息,然后運行階段根據具體類型作出不同的回應。
  

這就是Java泛型的核心概念:告訴編譯器想使用什么類型,然后編譯器幫你處理一切細節。

  泛型不僅可以應用於類上,還可以用於方法。而且擁有泛型方法跟所在的類是否是泛型類沒有關系。
  Java編程思想上還提到了一個基本的指導原則:
  

無論何時,只要你能做到,你就應該盡量使用泛型方法。也就是說,如果使用泛型方法可以取代整個類泛型化,那么就應該只使用泛型方法,因為它可以使事情更清楚明白。另外,對於一個 static的方法而言,無法訪問泛型類的類型參數,所以,如果static方法需要使用泛型能力,就必須使其成為泛型方法。

  定義泛型方法,就是將泛型的參數列表放在返回值之前即可。

  關於類型擦除,就是 ArrayList<Integer>ArrayList<String>在運行的時候其實是一種類型。即任何具體的類型信息都被擦除,這兩種形式都被擦除為最原生態的方式就是ArrayList。
  extends和super關鍵字的使用:首先要注意的是即使Apple是Fruit,Apple的List也不是Fruit的List,Apple的List只能持有Apple及其子類,而Fruit可以持有所有水果。如果我們想建立兩種帶參容器的向上轉型關系,就使用extends,例如List<? extends Fruit> fruits = new ArrayList<Apple>();但是我不能往里面添加任何Apple、Fruit甚至是Object類對象,按照編程思想說的,add()的參數此時變成了"? extends Fruit",編譯器不能了解需要Fruit的具體子類型,所以只會接受null。不過能確保的是這個列表中的對象至少都是Fruit類型的。至於super(超類型通配符),我們可以使參數類型為<? super T>的容器持有T或者是T的子類。
  ?是無界通配符,當我們不知道具體實際類型的時候,就很好用。
  最后要注意的是任何基本類型都不能作為類型參數。解決的辦法就是使用自動包裝機制。
  總之,泛型是使用起來簡單、方便的語法,但是自己編寫泛型代碼確是一件非常累的事情。編程思想洋洋灑灑花了將近100頁來寫泛型就可見一斑。


2.Java Q&A

1.List中指定元素的刪除

1.1 實驗總結

  針對樣例中出現的數量不等的空格,使用正則表達式的貪婪原則將它們分開來String[] strings = line.split(" +");java中split任意數量的空白字符
  還有就是在remove的過程當中,刪除當前下標為i的元素后,該元素后的所有元素將往前移一格,所以i這時候需要自減一次。這樣可以確保所有元素都可以不被遺漏地檢測。
  另一種安全刪除的方法就是使用迭代器進行遍歷,然后調用迭代器的remove()方法來移除當前對象。如何正確刪除List中的元素
  Iterator的remove()方法移除迭代器最后返回的一個元素,在調用remove()方法前必須調用next()方法。而且注釋中還指出remove()只是一個可選方法,當某個迭代器不支持remove()方法,但是還是調用了remove()方法,就會拋出UnsupportedOperationException的異常。


1.2 截圖你的提交結果(出現學號)


2.統計文字中的單詞數量並按出現次數排序

2.1 偽代碼(簡單寫出大體步驟)

for each word in text
    put it in the map and the count increments

make a list to record the pair of the key and the corresponding value

according to the value and the key sort the list

n = min(the size of list, 10)
for i = 0 to n - 1
    print the ith pair


2.2 實驗總結

  首先這邊用HashMap即可,雖然按照題目的要求需要進行排序,但是我們可以放到列表當中來完成操作。
  這邊來講一下Map的一些操作。
  比如get()方法。當鍵不在容器中時,get()方法將返回null,在本例中,就表明單詞第一次在文章當中出現,否則就會返回對應的值。
  put()方法是用來往Map容器里面添加鍵值對的,如果出現有鍵相同的情況,則會用新值去取代舊值。Java的Map統計次數似乎比C++麻煩一些,或許是我不清楚,假如用C++的Map來統計次數的話,只要根據鍵像數組下標那樣訪問對應的值,並自增即可,而Java需要重新put進去。
  Map可以用keySet()方法返回鍵的Set,values()方法來返回值的Collection,或者用entrySet()方法來返回鍵值對的Set,這邊用到的就是這第三種方法。


2.3 截圖你的提交結果(出現學號)


3.倒排索引

3.1 偽代碼(簡單寫出大體步驟)

create a map from word to a sorted set
for line in the paragraph
	for word in line
		add the number of line in the set of the word
for each search
	compute the intersection of the sets of the words
	if the intersection is empty
		print found 0 results
	else 
		print the elements of the set

3.2 實驗總結

  要注意單詞找不到的情況,只要有一個單詞找不到,返回空集即可。還有就是和前面一樣輸入輸出的問題,在統計的時候可以使用next()方法來逐個吃單詞,在查詢的時候則要先讀取一行,再對單詞進行分割。

3.3 截圖你的提交結果(出現學號)


4.Stream與Lambda

編寫一個Student類,屬性為:
private Long id;
private String name;
private int age;
private Gender gender;//枚舉類型
private boolean joinsACM; //是否參加過ACM比賽

創建一集合對象,如List,內有若干Student對象用於后面的測試。

4.1 使用傳統方法編寫一個方法,將id>10,name為zhang, age>20, gender為女,參加過ACM比賽的學生篩選出來,放入新的集合。在main中調用,然后輸出結果。

public static ArrayList<Student> choose(ArrayList<Student> arrayList) {
	ArrayList<Student> arrayList2 = new ArrayList<Student>();
	for (Student student : arrayList) {
		if (student.getId() > 10L && student.getName().equals("zhang")
				&& student.getAge() > 20 && 
				student.getGender().equals(Gender.女)
				&& student.isJoinsACM()) {
			arrayList2.add(student);
		}
	}
	return arrayList2;
}

4.2 使用java8中的stream(), filter(), collect()編寫功能同4.1的函數,並測試。

ArrayList<Student> arrayList2 = (ArrayList<Student>) arrayList.parallelStream()
		.filter(student -> (student.getId() > 10L && student.getName().equals("zhang")
				&& student.getAge() > 20 && 
				student.getGender().equals(Gender.女)
				&& student.isJoinsACM()))
		.collect(Collectors.toList());

測試結果同4.1圖

4.3 構建測試集合的時候,除了正常的Student對象,再往集合中添加一些null,然后重新改寫4.2,使其不出現異常。

ArrayList<Student> arrayList2 = (ArrayList<Student>) arrayList.parallelStream()
		.filter(student -> student != null && (student.getId() > 10L && student.getName().equals("zhang")
				&& student.getAge() > 20 && 
				student.getGender().equals(Gender.女)
				&& student.isJoinsACM()))
		.collect(Collectors.toList());

那就只要再加上student != null這句話就好了,就是上來就判斷非空。


5.泛型類:GeneralStack

5.1 GeneralStack接口的代碼

interface GeneralStack<E> {
	E push(E e);            
	E pop();                 
	E peek();                
	boolean empty();
	int size();
}

5.2 結合本題,說明泛型有什么好處

  一般的類或者是方法,都只能使用具體的類型,要么是具體類型,要么是自定義的類,這樣如果要編寫應用於多種類型的代碼,就要針對每一個類寫對應的代碼,非常僵硬。
  泛型可以使我們的代碼應用於多種類型。
  

使用泛型類型機制的最吸引人的地方,就是在使用容器類的地方。

在泛型出現之前,將一個對象放在一個容器中,這個對象會被向上轉型為Object,當然這樣就會丟失類型信息。然后要把這個對象從容器中取回的時候,就得向下轉型成一個正確的類型。就像書上說的,把一個Dog放在一個Cat的List中,是沒有任何問題的。但是我要把它轉型為Cat的時候就會拋出異常,但是我們只有在運行的時候才能發現。這是泛型在帶來更加通用代碼的一個副作用,即創建類型安全的容器。

5.3 截圖你的提交結果(出現學號)


6.泛型方法

6.1 編寫方法max,該方法可以求出List中所有元素的最大值,並返回。List中的元素必須實現Comparable接口。編寫的max方法使得String max = max(strList)可以運行成功,其中strList為List 類型。

public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll) {
	return Collections.max(coll);
}


//test
ArrayList<String> arrayList = new ArrayList<String>();
arrayList.add("abc");
arrayList.add("cccc");
arrayList.add("bbb");
System.out.println(max(arrayList));


6.2 編寫方法max1,基本功能同6.1,但讓其所返回的值可以賦予其父類型變量。如有User類,其子類為StuUser,且均實現了Comparable接口。編寫max1使得User user = max1(stuList);可以運行成功,其中stuList為List<StuUser>類型。也可使得Object user = max(stuList)運行成功。

public static <T> T max(Collection<? extends T> coll, Comparator<? super T> comp) { 
	return Collections.max(coll, comp);
}

public static void main(String[] args) {
	ArrayList<StuUser> arrayList = new ArrayList<StuUser>();
	arrayList.add(new StuUser(10, "1"));
	arrayList.add(new StuUser(20, "4"));
	arrayList.add(new StuUser(15, "6"));
	User user = max(arrayList, new StuUserComparator());
	System.out.println(user);
	Object user1 = max(arrayList, new UserReverseComparator());
	System.out.println(user1);
}

返回的StuUser類型向上轉型應該是沒有什么問題的吧


6.3 選做:編寫int myCompare(T o1, T o2, Comparator c)方法,該方法可以比較User對象及其子對象,傳入的比較器c既可以是Comparator<User>,也可以是Comparator<StuUser>。注意:該方法聲明未寫全,請自行補全。

public static<T> int myCompare(T o1, T o2, Comparator<T> c) {
	return c.compare(o1, o2);
	
}

public static void main(String[] args) {
	StuUser stuUser = new StuUser(10, "1");
	StuUser stuUser2 = new StuUser(20, "4");
	User user = new User(15);
	System.out.println(stuUser);
	System.out.println(stuUser2);
	System.out.println(user);
	System.out.println(myCompare(stuUser, stuUser2, new StuUserComparator()));
	System.out.println(myCompare(stuUser, user, new UserReverseComparator()));
}


  


7.選做:逆向最大匹配分詞算法

7.1 寫出偽代碼即可

for word in dict
    add in the set
new a list
while input a sentence
    clear the list
    for i in range the length of sentence to 0
        for j in range 0 to i - 1
            string <- the substring from j to i
            if the set contains the string
                add in the list
                break
        if j equals to i - 1
            add the substring from j to i in the list
            
        i <- j
    reverse the list
    output the list

  因為分詞的要求是逆向匹配最大,所以這邊每次查詢的時候都應該從字符串的最左邊開始,然后因為外循環是從后面加到前面,所以最后如果是按照詞語在句子當中的次序輸出的話,就要逆置列表。


7.2 截圖你的代碼運行結果。


8.JavaFX入門

完成其中的作業1、作業2。內有代碼,可在其上進行適當的改造。建議按照里面的教程,從頭到尾自己搭建。
  
  進去的界面

  顯示Muster的詳細信息

  添加新的Person

  修改Anna的信息


  把Werner刪了


3.碼雲上代碼提交記錄及PTA實驗總結

3.1 碼雲代碼提交記錄

  • 在碼雲的項目中,依次選擇“統計-Commits歷史-設置時間段”, 然后搜索並截圖


看的不過癮的請點下面
回到頂部



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM