《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语句中展示所有的使用方式。

猜你喜欢

转载自blog.csdn.net/lanzijingshizi/article/details/84557240