《JAVA编程思想》的学习

来源:互联网 发布:日本社交软件排名 编辑:程序博客网 时间:2024/05/21 17:51

今天第一次发表博客,也是因为我正在学习JAVA编程思想,想自己做个记录,也有个总结。

第十一章 持有对象

 引文:如果一个程序只包含固定数量的且其生命期都是已知的对象,那么这是一个非常简单的程序--来自《JAVA编程思想》

所JAVA有多种方式保存对象(应该说是对象的引用)。例如数组,他是编译器支持的类型。数组是保存一组对象的最有效的方式,如果你想保存一组基本类型数据,也推荐使用这种方式。但是数据具有固定的尺寸,而在更一般的情况中,你在写程序时并不知道将需要多少个对象,或者是否需要更复杂的方式去存储对象,因此数组尺寸固定这一限制显得过于受限了。

因此Java提供了大量只有对象的方式解决这个问题,其实集中于四种容器:Map,List,Set,Queue。

一:LIst接口

List接口实现主要有两种:1.ArrayList和ArrayList。
ArrayList:它随机访问元素比较快,但是在List的中间插入和移除元素时较慢。
LinkedList:它通过随机访问元素比较慢,但是在List的中间进行插入和删除较慢。
List必须按照插入的顺序保存元素。
ArrayList的简单实现:
package com.cn.collection;import java.util.ArrayList;class Apple{private static long counter;private final long id = counter++;public long id(){return id;}}class Orange{}public class ApplesAndOrangesWithoutGenerics {@SuppressWarnings("unchecked")public static void main(String[] args) {//前面的Apple是泛型,声明只能添加Apple类型对象。后面的Apple为返回值类型。ArrayList<Apple> apples = new ArrayList<Apple>();for (int i = 0; i < 3; i++) {apples.add(new Apple());}for (int i = 0; i < apples.size(); i++) {//你认为是ArrayList是Apple(),其实是Object的对象。System.out.println(apples.get(i).id());}for (int i = 0; i < apples.size(); i++) {System.out.println(apples.get(i).id());}}}
当你指定了某个类型作为泛型参数时,你并不仅限于只能将该确切类型的对象放置到容器。向上转型也可以作用于其他类型一样作用于泛型:
package com.cn.collection;import java.util.List;import java.util.ArrayList;import java.util.LinkedList;class A extends Apple{}class B extends Apple{}class C extends Apple{}class D extends Apple{}public class GenericsAndUpcasting {public static void main(String[] args) {List<Apple> arraylist = new LinkedList<Apple>();arraylist.add(new A());arraylist.add(new B());arraylist.add(new C());arraylist.add(new D());for (Apple c : arraylist) {System.out.println(c);}}}
因此,你可以将Apple的子类型添加到指定为保存Apple对象的容器中。
程序的输出是从Object默认的toString()方法产生的,该方法将打印类名,后面跟随着该对象的散列码的无符号十六进制表示。

LinkedList实现+具体方法表示:
package com.cn.collection;import typeinfo.pets.*;import java.util.*;public class LinkedListFeatures {public static void main(String[] args) {//Pet是一个类,已经Pet的各种子类型。(不需要深入了解)LinkedList<Pet> pets = new LinkedList<Pet>(Pets.arrayList(5));//输出:[Rat, Manx, Cymric, Mutt, Pug]System.out.println(pets);//获得节点的头节点System.out.println("pets.getFirst(): "+pets.getFirst());//获得当前节点System.out.println("pets.element(): "+pets.element());//查看顶部System.out.println("pets.peek(): "+pets.peek());//remove掉RatSystem.out.println("pets.remove(): "+pets.remove());//去掉首节点System.out.println("pets.removeFirst(): "+pets.removeFirst());//remove掉下一个节点System.out.println("pets.poll(): "+pets.poll());System.out.println(pets);//添加首节点pets.addFirst(new Rat());//添加到最后一个节点pets.offer(Pets.randomPet());System.out.println("After offer(): "+pets);//添加节点pets.add(Pets.randomPet());System.out.println("After add(): "+pets);pets.addLast(new Hamster());System.out.println("After addLast(): "+pets);System.out.println("pets.removeLast(): "+pets.removeLast());}}


Set不保存重复的元素,。如果你试图将相同对象的多个实例添加到Set中,那么它就会阻止这种重复现象。Set中最常被使用的是测试归属性,你可以很容易地询问某个对象是否在某个Set中。正因如此,查找就成为了Set中最重要的操作,因此通常选择一个HashSet的实现,它专门对快速查找进行了优化。
下面是使用存放Integer对象的HashSet的实例:
package com.cn.collection;import java.util.*;public class SetOfInteger {public static void main(String[] args) {Random rand = new Random(47);Set<Integer> set = new HashSet<Integer>();for(int i=0;i<10000;i++)    set.add(rand.nextInt(30));System.out.println(set);}}//输出:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]
Map:将对象映射到其他对象的能力是一种解决编程问题的杀手锏。例如,考虑一个程序,他将用来检查JAVA的Random类的随机性。理想情况下,Rondom可以将产生理想的数字分布,但要想测试它,则需要生产大量的随机数,并对落下各种不同范围的数字进行计数。Map可以很容易地解决该问题。
在本例中,键是由Random产生的数字,而值是该数字出现的次数:

package com.cn.collection;import java.util.*;public class Statistics {public static void main(String[] args) {//声明随机数Random ran = new Random(47);//建立Map持有对象。Map是个借口,HashMap是实现方法。Map<Integer,Integer> m = new HashMap<Integer,Integer>();//在一万个for循环中for (int i = 0; i < 10000; i++) {//将在29以内的随机数种赋给给rint r = ran.nextInt(29);//m添加随机数Integer frep = m.get(r);m.put(r, frep == null? 1:frep+1);}System.out.println(m);}}//输出:{0=323, 1=325, 2=332, 3=353, 4=367, 5=363, 6=341, 7=357, 8=340, 9=331, 10=328, 11=336, 12=352, 13=353, 14=353, 15=373, 16=349, 17=336, 18=336, 19=333, 20=355, 21=351, 22=369, 23=337, 24=360, 25=350, 26=344, 27=325, 28=328}

Queue:队列是一个典型的先进先出(FIFO)的容器。即从容器的一段放入事物,从另一端取出,并且事物放入容器的顺序和取出的顺序是相同的。队列常被当做一种可靠的将对象从程序的某个区域传输到另一个区域的途径。
package com.cn.collection;import java.util.*;public class QueueDemo {public static void printQ(Queue queue){while(queue.peek()!=null)System.out.println(queue.remove()+" ");    System.out.println();}public static void main(String[] args) {Queue<Integer> queue = new LinkedList<Integer>();Random ran = new Random(47);for (int i = 0; i < 10; i++)        queue.offer(ran.nextInt(i+10));printQ(queue);Queue<Character> qc = new LinkedList<Character>();for (char c : "Brontosaurus".toCharArray())                  qc.offer(c);printQ(qc);}}//输出:8 1 1 1 5 14 3 1 0 1 //B r o n t o s a u r u s 

Foreach与迭代器:到目前为止,foreach语法主要用于数组,但是它也可以应用于任何Collection对象。你实际上已经看到过很多使用ArrayList时用到它的实例,下面是一个更通用的证明:
package com.cn.collection;import java.util.*;public class IterableClass implements Iterable<String>{protected String[] words =("And that is how "+ "We know the Earth to be banana.").split(" ");public Iterator<String> iterator(){return new Iterator<String>(){private int index = 0;public boolean hasNext(){return index < words.length;}public String next(){return words[index++];}public void remove(){throw new UnsupportedOperationException();}};}public static void main(String[] args) {for (String s : new IterableClass())            System.out.println(s+" ");}}//输出:And that is how We know the Earth to be banana. 

小结:

1)数组将数字与对象联系起来。它保存类型明确的对象,查询对象时,不需要对结果做类型转换,它可以是多维的,可以保存基本类型数据。但是,数组一旦生成,其容量就不能改变。

2)Collection保存单一元素,而Map保存相关的键值对。有了Java泛型,你就可以指定容器中存放的对象,因此你就不会将错误的对象放入容器中,并且在容器中获取元素时,不必类型转换。各种Collection和各种Map都可以在你向其中添加元素时,自动调整其尺寸。容器不能持有基本类型,但是自动包装机制会仔细地执行基本类型到容器中所持有的包装器类型之间的双向转换。

3)像数组一样,List也建立数字索引与对象的关联,因此,数组和list都是排好序的容器,LIst能够自动扩充容量。

4)如果要大量的随机访问,就使用ArrayList,如果经常从表中插入或删除元素,则应该使用LinkedList.

5)各种Queue以及队列的行为由LinkedList提供支持。

6)Map是一种将对象(而非数字)与对象相关联的设计。HashMap设计用来快速访问;而TreeMap保持“键”始终处于排序状态,所以没有HashMap快,LinkedHashMap保持元素插入的顺序,但是也通过散列提供快速访问能力。

7)Set不接受重复元素。HashSet提供最快的查询速度,而TreeSet保持元素处于排序状态。LinkedHashSet以插入顺序保存元素。

8)新程序中不应该使用过时的Vector,Hashtable和Stack.