1. 程式人生 > >《Java程式設計思想》第11章 練習題

《Java程式設計思想》第11章 練習題

練習1:建立一個新類Gerbil(沙鼠),包含int gerbilNumber,在構造其中初始化它。新增一個方法hop(),用以列印沙鼠的號碼以及他正在跳躍的資訊,建立一個ArrayList,並向其中新增一串Gerbil物件,使用get()遍歷List,並且對每個Gerbil呼叫hop()。
練習2:修改SimpleCollection.java,使用Set表示c
練習3:修改innerclasses/Sequence.java,使你可以向其中新增任意數量的元素。
練習4:建立一個生成器類,它可以在每次呼叫其next()方法時,產生你由你最喜歡的電影的字元構成的名字(作為String

物件)。在字元列表中的電影名用完之後,迴圈到這個字元列表的開始出。使用這個生成器來填充陣列。ArrayListLinkedListHashSetLinkedHashSetTreeSet,然後列印每一個容器。
練習5:修改ListFeature.java,讓它使用Integer(記住自動包裝機制!)而不是Pet,並解釋在結果上有何不同。
答:我們知道容器類不能放基本型別的,放進放出都要先包裝和解包。這裡的裝箱應該理解為 封裝物件 ,即把基礎資料型別(如 int)轉換成基礎型別封裝類的物件(如 new Integer())。拆箱就是裝箱的反過程,即把基礎型別封裝類的物件(如 new Integer())轉換為基礎資料型別(如 int)。

裝箱: Integer a = new Integer() ;
              a = 100 ; //1.5以前不支援為物件如此賦值
拆箱: int b = new Integer(100) ;

List behavior varies depending on equals( ), as TIJ4 explains. Two Integers are equal if their contents are identical in the output.
Be vigilant with overloaded methods like remove( ); it’s easy to make mistakes due to autoboxing. If, for example, you type remove(2)

instead of remove(Integer.valueOf(2)) you remove the third element from the list (as the first element’s index is 0), instead of an element whose value is 2.
練習6:修改ListFeatures.java,讓它使用String而不是Pet,並解釋在結果上有何不同。
練習7:建立一個類,然後建立一個用你的類的物件進行過初始化的陣列。通過使用subList()方法,建立你的List子集,然後在你的List中移除這個子集。
練習8:修改練習1,以便呼叫
hop()時使用Iterator
遍歷List
練習9:修改innerclasses/Sequence.java,使得在Sequence中,用Iterator取代Selector
練習10:修改第8章中的練習9,使其使用一個ArrayList來存放Rodents,並使用一個Iterator來訪問Rodent序列。
練習11:寫一個方法,使用Iterator遍歷Collection,並列印容器中每個物件的toString()。填充各種型別的Collection,然後對其使用此方法。
練習12:建立並組裝一個List<Integer>,然後建立第二個具有相同尺寸的List<Integer>,並使用ListIterator讀取第一個List中的元素,然後再將它們以反序插入到第二個列表中。

package ch11;

import java.util.*;

public class E12 {
	public static void main(String[] args) {
		List<Integer> ints = new ArrayList<Integer>(
				Arrays.asList(1,2,3,4,5,6,7,8));
		ListIterator<Integer> fwd = ints.listIterator();
		
		List<Integer> ints1 = new ArrayList<Integer>(ints);
		ListIterator<Integer> rev = ints1.listIterator(ints1.size());//指向列表索引最後一個元素
		
		while(fwd.hasNext()){
			Integer tmp = fwd.next();
			rev.previous();//向前
			rev.set(tmp);
		}
		System.out.println("ints: "+ints);
		System.out.println("ints1: "+ints1);
	}
}/* Output:
ints: [1, 2, 3, 4, 5, 6, 7, 8]
ints1: [8, 7, 6, 5, 4, 3, 2, 1]
*///:~

練習13:在innerclasses/GreenhouseController.java示例中,Controller類使用的是ArrayList,修改程式碼,用LinkedList替換之,並使用Iterator來迴圈遍歷事件集。
練習14:建立一個空的LinkedList<Integer>,通過使用ListIterator,將若干個Integer插入這個List中,插入時,總是將它們插入到List的中間。

package ch11;

import java.util.*;

public class E14 {
	public static void main(String[] args) {
		LinkedList<Integer> ints = new LinkedList<Integer>();
		ListIterator<Integer> lit = ints.listIterator();
		for(int i=0;i<10;i++) {
			lit.add(i);
			if(i % 2 == 0)
				lit.previous();
		}
		System.out.println(ints);
	}
}/* Output:
[1, 3, 5, 7, 9, 8, 6, 4, 2, 0]
*///:~

插入過程如下:
在這裡插入圖片描述
練習15:棧在程式語言中經常用來對錶達式求值。請使用net.mindview.util.Stack對下面表示式求值,其中“+”表示“將後面的字母壓進棧”,而“-”表示“彈出棧頂字母並列印它”:“+U+n+c—+e+r+t—+a-+i-+n+t+y—+ -+r+u–+l+e+s—”。

package ch11;

import net.mindview.util.*;

public class E15 {
	public static void main(String[] args) {
		Stack<Character> stack = new Stack<Character>();
		String s = "+U+n+c---+e+r+t---+a-+i-+n+t+y---+ -+r+u--+l+e+s---";
		char data[] = s.toCharArray();
		for(int i=0;i<data.length;)
			switch(data[i++]){
			case '+' : stack.push(data[i++]);
						break;
			case '-' : System.out.print(stack.pop());
			}
	}
}/* Output:
cnUtreaiytn ursel
*///:~

練習16:建立一個母音字母Set。對UniqueWords.java操作,計數並顯示在每一個輸入單詞中的母音字母數量,並顯示輸入檔案中的所有母音字母的數量總和。

package ch11;

import java.util.*;
import net.mindview.util.*;

public class E16 {
	public static void main(String[] args) {
		Set<Character> vowels  = new HashSet<Character>(
				Arrays.asList('a','e','i','o','u','A','E','I','O','U'));
		HashSet<String> processedWords = new HashSet<String>();
		int fileVowel = 0;
		int wordVowel = 0;
		TextFile tf = new TextFile("src\\ch11\\UniqueWords.java","\\W+");
		for(String word:tf){
			wordVowel=0;
			
			for(char c:word.toCharArray())
				if(vowels.contains(c))
					wordVowel++;
			if(!processedWords.contains(word)){
				processedWords.add(word);
				System.out.println(word+" has "+wordVowel);
			}
			fileVowel += wordVowel;
		}
		System.out.println("Total number of vowels in file: " + fileVowel);
	}
}

練習17:使用練習1中的Gerbil類,將其放入Map中,將每個Gerbil的名字String(鍵)與每個Gerbil(值)關聯起來。為keySet()獲取Iteratror,使用它遍歷Map,針對每個“鍵”查詢Gerbil,然後打印出“鍵”,並讓gerbil執行hop()
練習18:用鍵值對填充一個HashMap。列印結果,通過雜湊碼來展示其排序。抽取這些鍵值對,按照鍵進行排序,並將結果置於一個LinkedHashMap中。展示其所維護的插入排序。
練習19:使用HashSetLinkedHashSet重複前一個練習。
練習20:修改練習16,使得你可以跟蹤每一個母音字母出現的次數。
練習21:通過使用Map<String,Integer>,遵循UniqueWords.java的形式來建立一個程式,它可以對一個檔案中出現的單詞計數。使用帶有第二個引數**String.CASE_INSENSITIVE_OREDER的Collection.sort()**方法對結果進行排序(將產生字母序),然後顯示結果。

package ch11;

import java.util.*;
import net.mindview.util.TextFile;

public class E21 {
	public static void main(String[] args) {
		TextFile tf = new TextFile("src\\ch11\\UniqueWords.java","\\W+");
		Map<String,Integer> wordCount = new HashMap<String,Integer>();
		for(String word:tf){
			Integer freq = wordCount.get(word);
			wordCount.put(word,freq==null?1:freq+1);
		}
		System.out.println(wordCount);
		List<String> keys = new ArrayList<String>(wordCount.keySet());
		Collections.sort(keys,String.CASE_INSENSITIVE_ORDER);
		for(String key : keys)
			System.out.print(key+"="+wordCount.get(key)+", ");
	}
}

練習22:修改前一個練習,使其用一個包含有一個String域和一個計數域的類來儲存每一個不同的單詞,並使用一個由這些物件構成的Set來維護單詞列表。

package ch11;

import java.util.*;
import net.mindview.util.*;

class WordCounter{
	public static final Comparator<WordCounter> CASE_INSENSITIVE_ORDER = 
			new Comparator<WordCounter>() {
		public int compare(WordCounter o1, WordCounter o2){
			return o1.word.compareToIgnoreCase(o2.word);
		}
	};
	private final String word;
	private int frequency;
	WordCounter(String word) {
		this.word = word;
		frequency = 1;
	}
	void incFrequency(){++frequency;}
	String getWord(){return word;}
	int getFrequency(){return frequency;}
	public boolean equals(Object o){
		return o instanceof WordCounter && word.equals(((WordCounter)o).word);
	}
	public int hashCode() {return word.hashCode(); }
}

public class E22 {
	static void updateStat(Iterator<WordCounter> it, WordCounter wc) {
		while(it.hasNext()) {
			WordCounter currentWC = it.next();
			if(currentWC.equals(wc))
				currentWC.incFrequency();
		}
	}
	public static void main(String[] args) {
		Set<WordCounter> stat = new HashSet<WordCounter>();
		for(String word : new TextFile("src\\ch11\\UniqueWords.java","\\W+")) {
			WordCounter wc = new WordCounter(word);
			if(stat.contains(wc))
				updateStat(stat.iterator(),wc);
			else
				stat.add(wc);
		}
		List<WordCounter> l = new ArrayList<WordCounter>(stat);
		Collections.sort(l,WordCounter.CASE_INSENSITIVE_ORDER);
		for(WordCounter wc : l)
			System.out.println(wc.getWord() + " => "+wc.getFrequency());
	}

}

The WordCounter class contains a String and a frequency field to store each different word. It uses equals( ) and hashCode( ) methods, respectively, to store class instances inside a HashSet.
We created a custom Comparator to use the Collections.sort( ) method in the last exercise. Here it acts like String.CASE_INSENSITIVE_ORDER.
Without a HashMap, the situation gets more complicated, which shows how useful it is to keep your code base as small as possible (and boost productivity) by learning the classes offered by the JDK.
Additionally, try a TreeSet instead of a bare HashSet to maintain the list of words, and compare what (if any) improvement this makes to the program.
練習23:從Statistics.java開始,寫一個程式,讓它重複做測試,觀察是否某個數字比別的數字出現的次數多。
練習24:使用String“鍵”和你選擇的物件填充LinkedHashMap。然後從中提取鍵值對,以鍵排序,然後重新插入此Map
練習25:建立一個Map<String,ArrayList<Integer>>,使用net.mindview.TextFile來開啟一個文字檔案,並一次讀入一個單詞。在讀入單詞時對它們進行計數,並且對於檔案中的每一個單詞,都在ArrayList<Integer>中記錄下與這個詞相關聯的單詞計數。實際上,它記錄的是該單詞在檔案中被發現的位置。
練習26:拿到前一個練習中所產生的Map,並按照它們在最初的檔案中出現的順序重新建立單詞順序。

package ch11;

import java.util.*;
import java.util.Map.Entry;

import net.mindview.util.TextFile;

public class E26 {
	public static void main(String args[]){
	       //E25
		Map<String,ArrayList<Integer>> m = new HashMap<String,ArrayList<Integer>>();
		int wordCount = 0;
		TextFile tf = new TextFile("src\\ch11\\E26.java","\\W+");
		for(String word : tf){
			ArrayList<Integer> l = m.get(word);
			if(l==null){
				l = new ArrayList<Integer>();
				m.put(word,l);
			}
			l.add(++wordCount);	
		}
		System.out.println(m);
		
		//E26 排序
		TreeMap<Integer,String> tm = new TreeMap<Integer,String>();
		for(Entry<String,ArrayList<Integer>> e : m.entrySet())
			for(int p : e.getValue())
				tm.put(p,e.getKey());
		
		System.out.println(tm);		
	}
}

練習27:寫一個稱為Command的類,它包含一個String域和一個顯示該Stringoperation()方法。寫第二類,它具有一個使用Command物件來填充一個Queue並返回這個物件的方法。將填充後的Queue傳遞給第三個類的一個方法,該方法消耗掉Queue中的物件,並呼叫它們的operation()方法。
練習28:用由java.util.Random建立的Double值填充一個PriorityQueue(用offer())方法,然後使用poll()移除並顯示它們。
練習29:建立一個繼承自Object的簡單類,它不包含任何成員,展示你不能將這個類的多個示例成功地新增到一個PriorityQueue中。這個問題將在第17章中詳細解釋。
練習30:修改CollectionSequeuece.java,使其不要繼承AbstractCollection,而是實現Collection
練習31:修改polymorphism/shape/RandomShapeGenerator.java,使其成為一個Iterable。你需要新增一個接受元素數量為引數的構造器,這個數量是指在停止之前,你想用迭代器生成的元素的數量。驗證這個程式可以工作。
練習32:按照MultiIterableClass示例,在NonCollectionSequence.java中新增reversed()和randomized()方法,並讓NonCollectionSequence實現Iterable。然後在foreach語句中展示所有的使用方式。