本文主要是介绍Thinking in java 第11章 持有对象 笔记+习题,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
Thinking in java 第11章 持有对象
学习目录
11.1 泛型和类型安全的容器
1. 当你制定了某个类型作为泛型参数时,你并不仅限于只能将该确切类型的对象放置到容器中。向上转型也可一样作用于泛型。
11.2 基本概念
1. Java容器被划分为两个概念:
- Collection:一个独立元素的序列,这些元素都服从一条或多条规则。
- Map:一组成对的“键值对”对象,允许你使用键来查找值。
11.3 添加一元素
1. Arrays.asList() 方法接收一个数组或是一个用逗号分隔的元素列表,并将其转换为一个List对象。
2. Collections.addAll() 方法接收一个Collection对象,以及一个数组或是一个用逗号分隔的列表。
Collections<Integer> collection = new ArrayList<Integer>(Arrays.asList(1,2,3,4,5));
Integer[] moreInts = {6,7,8,9,10};
collection.addAll(Array.asList(moreInts));Collections.addAll(collection, 11, 12, 13, 14, 15);
Collections.addAll(collection, moreInts);List<Integer> list = Arrays.asList(16,17,18,19,20);
list.set(1,99);
//! list.add(21); underlying array cannot be resized
3. 方法2只能接受Collection,因此没有方法1灵活;而方法1返回的底层是数组,不能改变大小(即不能add或delete)
11.4 容器的打印
1. Set类型:
- HashSet使用相当复杂的方式来存储元素,这种技术是最快的获取元素方式,因此顺序无实际意义。
- TreeSet按照比较结果的升序保存对象。
- LinkedHashSet按照被添加的顺序保存对象。
2. Map类型(Map.put(key, value); Map.get(key))
- HashMap提供了最快的查找技术,没有按照任何明显顺序来保存。
- TreeMap按照比较结果的升序保存键。
- LinkedHashMap按照插入顺序保存键,同时还留下了HashMap的查询速度。
11.5 List
1. 分为ArrayList和LinkedList,区别即顺序表和链表的区别。
2. 用contains()方法判断某个对象是否在列表中。
3. 用remove()方法移除某个对象。
4. 用indexOf()方法查询索引编号。
5. 比较要用到equals()方法,最好都重写。
6. 用subList()方法获取子集。
7. containsAll()、Collections.shuffle()、Collections.sort()、retainAll() 交集、removeAll()、set()、isEmpty()、clear()、toArray()
11.6 迭代器
1. 迭代器通常被称为轻量级对象:创建它的代价小。因此迭代器有很多奇怪的限制,例如Java的Iterator只能单向移动,只能用来:
- 使用iterator()要求容器返回一个Iterator。Iterator将准备好返回序列的第一个元素。
- 使用next()获得下一个元素。
- 使用hasNext()检查是否还有元素。
- 使用remove()将迭代器将最新的元素删除,所以必须先调用next()再用remove()。
2. 用Iterator<T> it 就能不管T的容器类型。
3. ListIterator是Iterator的子类,可以双向移动,还可以返回指向当前元素的前一个和后一个元素的索引,且可使用set()替换访问过的最后一个元素。 方法为:hasNext()、hasPrevious()、next()、previous()、nextIndex()、previousIndex()、set()
11.7 LinkedList
1. LinkedList添加了可以使其用作栈、队列或双端队列的方法,这些方法中有些彼此之间只是名字差异或只有轻微差异。如:
- getFirst()和element()完全一样,返回表头元素,若空抛出异常,而peek()方法在空时返回null;
- removeFirst()和remove()完全一样,一处表头,若空抛出异常,而poll()方法在空时返回null;
- addFirst();add()和addLast()相同;removeLast();
11.8 Stack
1. push(T v)、peek()、pop()、empty()、toString()
11.9 Set
1. Set具有与Collection完全一样的接口,因此没有任何额外功能,不像前面有两个不同的List。
2. HashSet使用的是散列数组;TreeSet使用的是红黑树;LinkedHashSet也使用了散列,并用链表维护插入顺序。
3. 在TreeSet中如果想不分大小写进行从小到大排序,则用 Set<String> words = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
4. 方法为 add() 、 remove() 等。
11.10 Map
1. 添加时如下:
Integer freq = m.get(r);
m.put(r, freq == null? 1 : freq+1);
2. 可扩展到多维,即value可以使其他容器。
3. 遍历时如下:
for(T t : map.keySet())print(t + ": " + map.get(t));
11.11 Queue
1. 可以将LinkedList向上转型为Queue,因为其实现了Queue接口。故可写成 Queue<Integer> q = new LinkedList<Integer>();
2. 方法:offer() 插入队尾、peek()/element()、poll()/remove() 等。
3. PriorityQueue<T>,Collections.reverseOrder()产生反序的Comparator。
4. 如果你想在优先队列中使用自己的类,就必须包括额外的功能以产生自然排序,或者必须提供自己的Comparator。
11.12 Collection和Iterator
1. 在基于两个接口都能实现时(例如遍历输出),用Collection方便一些,因为它是Iterable的,用Foreach语句更加清晰。
2. 当要实现一个不是Colletion的外部类时,用Iterator更好。因为实现Collection必须要实现iterator(),而且还必须要实现其他一些方法。
11.13 Foreach迭代器
1. 如果你创建了任何实现Iterable的类,都可以将它用于Foreach语句中。
class A implements Iterable<T> {protected T[] words = ...;public Iterable<T> iterator() {return new Iterable<T>() {private int index = 0;public boolean hasNext() { return index < words.length; }public T next() { return words[index++]; }public void remove() {...}}}
}
2. Map的Foreach遍历如下:
for(Map.Entry entry : m.entrySet()) {print(entry.getKey(), entry.getValue());
}
3. 可以通过适配器方法,在类中添加用于不同作用的迭代方法。
习题
练习1:创建一个新类Gerbil(沙鼠),包含int gerbilNumber,在构造器中初始化它.添加一个方法hop(),用以打印沙鼠的号码以及它正在跳跃的信息。创建一个ArrayList,并向其中添加一串Gerbil对象。使用get()遍历List,并且对每个Gerbil调用hop()。
package Chapter11;import java.util.ArrayList;
import java.util.Arrays;public class E1 {public static void main(String[] args) {ArrayList<E1Gerbil> list = new ArrayList<E1Gerbil>(Arrays.asList(new E1Gerbil(1), new E1Gerbil(2),new E1Gerbil(3), new E1Gerbil(4)));for(E1Gerbil e : list) {e.hop();}}
}class E1Gerbil {private int gerbilNumber;public E1Gerbil(int gerbilNumber) {this.gerbilNumber = gerbilNumber;}public int getGerbilNumber() {return gerbilNumber;}public void setGerbilNumber(int gerbilNumber) {this.gerbilNumber = gerbilNumber;}public void hop() {System.out.println("" + gerbilNumber + " is jumping");}
}/*
1 is jumping
2 is jumping
3 is jumping
4 is jumping
*/
练习2:修改SimpleCollection.java,使用Set来表示c。
略。
练习3:修改innerclasses/Sequence.java,使你可以向其中添加任意数量的元素。
略。把Object[] 改为ArrayList<Object> ,并用相应的方法替换即可。(P192)
练习4:创建一个生成器类,它可以在每次调用其next()方法时,产生你最喜欢的电影的名字。在电影名列表的名字用完之后,循环到该列表的开始处。使用这个生成器来填充数组、ArrayList、LinkedList、HashSet、LinkedHashSet和TreeSet,然后打印每个容器。
package Chapter11;import java.util.*;public class E4 {public static void main(String[] args) {System.out.println("ArrayList " + new E4Generator().fill(new ArrayList<String>()));System.out.println("LinkedList " + new E4Generator().fill(new LinkedList<String>()));System.out.println("HashSet " + new E4Generator().fill(new HashSet<String>()));System.out.println("LinkedHashSet " + new E4Generator().fill(new LinkedHashSet<String>()));System.out.println("TreeSet " + new E4Generator().fill(new TreeSet<String>()));}
}class E4Generator {private String[] movies = {"ZZ", "BB", "CC", "AA", "FF", "EE"};private int maxLength = 6;private int i = 0;public String next() { return movies[(i++)%maxLength]; }public Collection<String> fill(Collection<String> c) {for(int j = 0; j < 8; j++) {c.add(next());}return c;}
}/*
ArrayList [ZZ, BB, CC, AA, FF, EE, ZZ, BB]
LinkedList [ZZ, BB, CC, AA, FF, EE, ZZ, BB]
HashSet [ZZ, BB, CC, AA, FF, EE]
LinkedHashSet [ZZ, BB, CC, AA, FF, EE]
TreeSet [AA, BB, CC, EE, FF, ZZ]
*/
练习5-练习6:修改LIstFeatures.java,让它用Integer/String而不是Pet,并解释在结果上有何不同。
略。
练习7:创建一个类,然后创建一个用你的类的对象进行过初始化的数组。通过使用subList()方法,创建你的List子集,然后在你的List中移除这个子集。
package Chapter11;import java.util.*;public class E7 {public static void main(String[] args) {E7A[] es = new E7A[] {new E7A(1), new E7A(2), new E7A(3), new E7A(4)};List<E7A> list = new ArrayList<E7A>(Arrays.asList(es));List<E7A> list2 = list.subList(1, 2);System.out.println(list2);list.removeAll(list2);System.out.println(list);}
}class E7A {int a;public E7A(int a) {this.a = a;}@Overridepublic String toString() {return Integer.toString(a);}}/*
[2]
[1, 3, 4]
*/
练习8:修改练习题1,以便调用hop()时使用Iterator遍历List。
package Chapter11;import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;public class E1 {public static void main(String[] args) {ArrayList<E1Gerbil> list = new ArrayList<E1Gerbil>(Arrays.asList(new E1Gerbil(1), new E1Gerbil(2),new E1Gerbil(3), new E1Gerbil(4)));Iterator<E1Gerbil> iter = list.iterator();while(iter.hasNext()) {iter.next().hop();}}
}class E1Gerbil {private int gerbilNumber;public E1Gerbil(int gerbilNumber) {this.gerbilNumber = gerbilNumber;}public int getGerbilNumber() {return gerbilNumber;}public void setGerbilNumber(int gerbilNumber) {this.gerbilNumber = gerbilNumber;}public void hop() {System.out.println("" + gerbilNumber + " is jumping");}
}/*
1 is jumping
2 is jumping
3 is jumping
4 is jumping
*/
练习9:修改innerclasses/Sequence.java,使得在Sequence中,用Iterator取代Selector。
略。用个方法return collection.iterator()即可。
练习10:修改第8章中的练习9,使其使用一个ArrayList来存放Rodents,并使用一个Iterator来访问Rodent序列。
略。
练习11:写一个方法,使用Iterator遍历Collection,并打印容器中每个对象的toString()。填充各种类型的Collection,然后对其使用此方法。
同P227代码。略。
练习12:创建并组装一个List<Integer>,然后创建第二个具有相同尺寸的List<Integer>,并使用ListIterator读取第一个List中的元素,然后再将它们以反序插入到第二个列表中。
package Chapter11;import java.util.*;public class E12 {public static void main(String[] args) {List<Integer> list1 = new ArrayList<>(Arrays.asList(1,2,3,4,5,6));List<Integer> list2 = new ArrayList<>();ListIterator<Integer> iter = list1.listIterator();while(iter.hasNext()) iter.next();while(iter.hasPrevious()) list2.add(iter.previous());System.out.println(list2);}
}/*
[6, 5, 4, 3, 2, 1]
*/
直接写 ListIterator<Integer> iter = list1.listIterator(list1.size()); 更好。
练习13:在innerclasses/GreenhouseController.java示例中,Controller类使用的是ArrayList,修改代码,用LinkedList替换之,并使用Iterator来循环遍历事件集。
略。简单应用。
练习14:创建一个空的LinkedList<Integer>,通过使用ListIterator,将若干个Integer插入这个List中,插入时,总是将它们插入到List的中间。
package Chapter11;import java.util.*;public class E14 {public static void main(String[] args) {List<Integer> list = new LinkedList<Integer>();for(int i = 0; i < 10; i++) {ListIterator iter = list.listIterator(list.size()/2);iter.add(i);}System.out.println(list);}
}/*
[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 Chapter11;import java.util.Stack;public class E15 {public static void main(String[] args) {String s = "+U+n+c---+e+r+t---+a-+i-+n+t+y---+ -+r+u--+l+e+s---";Stack<Character> stack = new Stack<>();for(int i = 0; i < s.length(); i++) {if(s.charAt(i) == '+') stack.push(s.charAt(++i));else System.out.print(stack.pop());}System.out.println();}
}/*
cnUtreaiytn ursel
*/
练习16:创建一个元音字母Set。对UniqueWords.java操作,计数并显示在每一个输入单词中的元音字母数量,并显示输入文件中的所有元音字母的数量总和。
没有文件,简单应用。略。
练习17:使用练习1中的Gerbil类,将其放入Map中,将每个Gerbil的名字String(键)与每个Gerbil(值)关联起来。为keySet()获取Iteratror,使用它遍历Map,针对每个“键”查询Gerbil,然后打印出“键”,并让gerbil执行hop()。
package Chapter11;import java.util.*;
import Chapter11.E1Gerbil;public class E17 {public static void main(String[] args) {ArrayList<E1Gerbil> list = new ArrayList<E1Gerbil>(Arrays.asList(new E1Gerbil(1), new E1Gerbil(2),new E1Gerbil(3), new E1Gerbil(4)));String name = "GG";Map<String, E1Gerbil> m = new HashMap<>();for(int i = 1; i < 5; i++) m.put(name+i, list.get(i-1));for(String s : m.keySet()) m.get(s).hop();}
}/*
1 is jumping
3 is jumping
2 is jumping
4 is jumping
*/
练习18:用键值对填充一个HashMap。打印结果,通过散列码来展示其排序。抽取这些键值对,按照键进行排序,并将结果置于一个LinkedHashMap中。展示其所维护的插入排序。
package Chapter11;import java.util.*;public class E18 {public static void main(String[] args) {Map<String, Integer> m = new HashMap<>();m.put("asd",1);m.put("zsdf",2);m.put("bgfd",3);System.out.println(m);List<String> strings = new LinkedList<>(m.keySet());Collections.sort(strings);Map<String, Integer> m2 = new LinkedHashMap<>();for(String s : strings) {m2.put(s, m.get(s));}System.out.println(m2);}
}/*
{zsdf=2, asd=1, bgfd=3}
{asd=1, bgfd=3, zsdf=2}
*/
练习19:使用HashSet和LinkedHashSet重复前一个练习。
这也能重复?略。
练习20:修改练习16,使得你可以跟踪每一个元音字母出现的次数。
略。
练习21:通过使用Map<String,Integer>,遵循UniqueWords.java的形式来创建一个程序,它可以对一个文件中出现的单词计数。使用带有第二个参数**String.CASE_INSENSITIVE_OREDER的Collection.sort()方法对结果进行排序(将产生字母序),然后显示结果。
package Chapter11;import java.util.*;public class E21 {public static void main(String[] args) {String[] s = "Can you can can a can?".split(" ");Map<String, Integer> map = new HashMap<>();for(String i : s) {Integer temp = map.get(i);map.put(i, (temp==null?1:temp+1));}List<String> list = new ArrayList<>(map.keySet());Collections.sort(list, String.CASE_INSENSITIVE_ORDER);for(String i : list) {System.out.println(i + " : " + map.get(i));}}
}/*
a : 1
Can : 1
can : 2
can? : 1
you : 1
*/
练习22:修改前一个练习,使其用一个包含有一个String域和一个计数域的类来存储每一个不同的单词,并使用一个由这些对象构成的Set来维护单词列表。
package Chapter11;import java.util.Objects;
import java.util.*;public class E22 {public static void main(String[] args) {String[] s = "Can you can can a can?".split(" ");Set<E22A> set = new HashSet<>();for(String i : s) {E22A e = new E22A(i);if(set.contains(e)) {Iterator<E22A> iter = set.iterator();while(iter.hasNext()) {E22A tempe = iter.next();if(tempe.equals(e)) tempe.add();}}else {e.setA(1);set.add(e);}}for(E22A e : set) {System.out.println(e.getS() + " : " + e.getA());}}
}class E22A {private String s;private int a;public void add() { a++; }public E22A(String s) {this.s = s;}public String getS() {return s;}public void setS(String s) {this.s = s;}public int getA() {return a;}public void setA(int a) {this.a = a;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;E22A e22A = (E22A) o;return Objects.equals(s, e22A.s);}@Overridepublic int hashCode() {return Objects.hash(s);}
}/*
a : 1
can? : 1
Can : 1
can : 2
you : 1
*/
要重写equals再调用contains()。
练习23:从Statistics.java开始,写一个程序,让它重复做测试,观察是否某个数字比别的数字出现的次数多。
package Chapter11;import java.util.HashMap;
import java.util.Map;
import java.util.Random;public class E23 {public static void main(String[] args) {Random r = new Random();Map<Integer, Integer> map = new HashMap<>();for (int i = 0; i < 10000; i++) {int temp = r.nextInt();Integer in = map.get(temp);map.put(temp, (in == null ? 1 : in+1));}for(Integer i : map.keySet()) System.out.println(""+i+" : "+map.get(i));}
}....
都只出现一次的样子。
练习24:使用String“键”和你选择的对象填充LinkedHashMap。然后从中提取键值对,以键排序,然后重新插入此Map。
略。和前面差不多。
练习25:创建一个Map<String,ArrayList<Integer>>,使用net.mindview.TextFile来打开一个文本文件,并一次读入一个单词。在读入单词时对它们进行计数,并且对于文件中的每一个单词,都在ArrayList<Integer>中记录下与这个词相关联的单词计数。实际上,它记录的是该单词在文件中被发现的位置。
略。计数就是ArraList.size()。
练习26:拿到前一个练习中所产生的Map,并按照它们在最初的文件中出现的顺序重新创建单词顺序。
略。最后再遍历一遍用LinkedHashSet存储。
练习27:写一个称为Command的类,它包含一个String域和一个显示该String的operation()方法。写第二类,它具有一个使用Command对象来填充一个Queue并返回这个对象的方法。将填充后的Queue传递给第三个类的一个方法,该方法消耗掉Queue中的对象,并调用它们的operation()方法。
package Chapter11;import java.util.*;public class E27 {public static void main(String[] args) {E27C.func2();}
}class E27A {private String s;public void operation() {System.out.println("this is " + s);}public E27A(String s) {this.s = s;}
}class E27B {public static Queue<E27A> func1() {return new LinkedList<>(Arrays.asList(new E27A("aaa"), new E27A("bbb"), new E27A("ccc")));}
}class E27C {public static void func2() {Queue<E27A> q = E27B.func1();while(!q.isEmpty()) {q.poll().operation();}}
}/*
this is aaa
this is bbb
this is ccc
*/
练习28:用由java.util.Random创建的Double值填充一个PriorityQueue(用offer())方法,然后使用poll()移除并显示它们。
略。同上。
练习29:创建一个继承自Object的简单类,它不包含任何成员,展示你不能将这个类的多个示例成功地添加到一个PriorityQueue中。这个问题将在第17章中详细解释。
问号。看完17章再来看看能不能答。
练习30:修改CollectionSequeuece.java,使其不要继承AbstractCollection,而是实现Collection。
略。直接实现Collection<Pet>接口要同时实现里面的多余的方法。
练习31:修改polymorphism/shape/RandomShapeGenerator.java,使其成为一个Iterable。你需要添加一个接受元素数量为参数的构造器,这个数量是指在停止之前,你想用迭代器生成的元素的数量。验证这个程序可以工作。
略。
练习32:按照MultiIterableClass示例,在NonCollectionSequence.java中添加reversed()和randomized()方法,并让NonCollectionSequence实现Iterable。然后在foreach语句中展示所有的使用方式。
略。同P244。
这篇关于Thinking in java 第11章 持有对象 笔记+习题的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!