十一、持有对象

 

 

 

书中的原标题是——holding your object,把握你的对象,译者翻译成持有对象。这是用的最多的类之一。

 

作者说的,如果一个程序包含固定数量的且其生命周期都是已知的对象,那么这是一个非常简单的程序。确实,如果数组大小已知,那么就很简单了。

 

除了数组,Java提供了容器类来holding object。

 

1)泛型和类型安全的容器

ArrayList,可以自动扩充大小的数组,add插入对象,get访问对象,size查看对象数目。

 

[java] view plain copy  print?

  1. class Apple{}  
  2.   
  3. public class Box {  
  4.     public static void main(String[] args) {  
  5.         ArrayList<Apple> a = new ArrayList<Apple>();  
  6.         a.add(new Apple());  
  7.     }  
  8. }  


泛型(就是跟在ArrayList后面的那个尖括号指明Apple类型的标识)的添加可以在编译期间防止将错误类型的对象放进容器中。

 

同样,容器也可以用foreach语法。

 

2)概念

容器类作用是保存对象。分为两个:

一、Collection,List顺序保存元素,Set不能有重复元素,Queue按照排队来。

二、Map,键值对,通过键找值或者被称为字典。

 

对了,写了这么多篇,忘记说一件重要的事情了,懂得查API文档,最好看英文版。Collection是什么,类还是接口,一查就知道了。

 

[java] view plain copy  print?

  1. public interface List<E>  
  2. extends Collection<E>  
  3.   
  4.   
  5. public class ArrayList<E>  
  6. extends AbstractList<E>  
  7. implements List<E>, RandomAccess, Cloneable, Serializable  

这样的关系就出来了。

 

3)添加一组元素

 

[java] view plain copy  print?

  1. public class AddGroup {  
  2.     public static void main(String[] args) {  
  3.         Collection<Integer> c = new ArrayList<Integer>(Arrays.asList(1,2,3,4));  
  4.         Integer[] group = {5,6,7,8 };  
  5.         c.addAll(Arrays.asList(group));  
  6.         System.out.println(c);  
  7.         Collections.addAll(c, 9,0);  
  8.         System.out.println(c);  
  9.     }  
  10. }  
  11.   
  12. //[1, 2, 3, 4, 5, 6, 7, 8]  
  13. //[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]  

 

 

 

Collections.addAll,Adds all of the specified elements to the specified collection.

将其他元素添加到Collection c中,而Collection.addAll是添加一组元素。

 

4)容器的打印

其实上面的代码已经看出,具体的容器已经实现了自己的toString方法。

 

5)List

List有两种:ArrayList,随机访问元素快,中间插入和删除操作慢。

                     LinkedList,随机访问慢,但是中间插入和删除快,类似链表。

 

List常用方法:

 

[java] view plain copy  print?

  1. class Member{  
  2.     int age;  
  3.     Member(int i){  
  4.         age = i;  
  5.     }  
  6.     public String toString(){  
  7.         return "member"+age;  
  8.     }  
  9. }  
  10.   
  11. public class ListMethod {  
  12.     public static void main(String[] args) {  
  13.         List<Member> members = new ArrayList<Member>();  
  14.         Member member1 = new Member(1);  
  15.           
  16.         //添加元素  
  17.         members.add(member1);  
  18.           
  19.         //判断容器是否为空  
  20.         System.out.println(members.isEmpty());  
  21.           
  22.         //判断容器是否包含该元素  
  23.         System.out.println(members.contains(member1));  
  24.           
  25.         //显示索引  
  26.         System.out.println(members.indexOf(member1));  
  27.           
  28.         //移除元素  
  29.         members.remove(member1);  
  30.         System.out.println(members);  
  31.           
  32.         Member member2 = new Member(2);  
  33.         Member member3 = new Member(3);  
  34.         Member member4 = new Member(4);  
  35.         members.add(member2);  
  36.         members.add(member3);  
  37.         members.add(member4);  
  38.           
  39.         //类似subString,从索引0开始截取到1,包含0和1  
  40.         System.out.println(members.subList(02));  
  41.           
  42.         //移除 不同于remove  
  43.         //removeAll(Collection<?> c)   
  44.         //remove(int index)   remove(Object o)   
  45.         members.removeAll(members);  
  46.         System.out.println(members);  
  47.     }  
  48.       
  49. }  


6)迭代器

 

在没用迭代器之前,遍历是这样写的:

 

[java] view plain copy  print?

  1. for(int i = 0; i < newList.size(); i++){  
  2.     System.out.println(newList.get(i));  
  3. }  


而迭代器被称为轻量级对象,创建的代价小。

 

 

 

 

[java] view plain copy  print?

  1. Iterator<Member> iterator = members.iterator();  
  2. while(iterator.hasNext()){  
  3.     System.out.println(iterator.next());  
  4. }  


next移动下一个元素,但是拿到的当前元素。hasNext检查是否还有元素,Iteratorf容器返回一个Iterator。

 

 

7)ListIterator

这个之前没听过,Iterator只能向前移动,ListIterator可以双向移动。

 

[java] view plain copy  print?

  1. ListIterator<Member> iterator = members.listIterator();  
  2. while(iterator.hasNext()){  
  3.     System.out.println(iterator.next());  
  4. }  
  5.   
  6. while(iterator.hasPrevious()){  
  7.     System.out.println(iterator.previous());  
  8. }  


向前输出,向后输出。

 

 

8)LinkedList

插入移除高效。

方法很容易理解,属于自解释型的方法名。

 

[java] view plain copy  print?

  1. public class TestLinkedList {  
  2.     public static void main(String[] args) {  
  3.         LinkedList<Member> members = new LinkedList<Member>();  
  4.         Member member1 = new Member(1);  
  5.         Member member2 = new Member(2);  
  6.         Member member3 = new Member(3);  
  7.         members.add(member1);  
  8.         members.add(member2);  
  9.         members.add(member3);  
  10.           
  11.         //返回列表头  
  12.         System.out.println(members.peek());  
  13.           
  14.         //移除并返回列表头  
  15.         System.out.println(members.removeFirst());  
  16.         System.out.println(members);  
  17.           
  18.         //返回并移除表头  
  19.         System.out.println(members.poll());  
  20.         System.out.println(members);  
  21.           
  22.         //removelast 移除最后一个  
  23.         members.add(member1);  
  24.         members.add(member2);  
  25.         System.out.println(members.removeLast());  
  26.         System.out.println(members);  
  27.           
  28.           
  29.         //addLast和add一样 都是往列表尾插入元素 addFirst自然就是表头  
  30.         members.add(member2);  
  31.         members.addFirst(member2);  
  32.         members.addLast(member2);  
  33.         System.out.println(members);  
  34.     }  
  35. }  

 

10)Set

Set,元素不重复。

Set与Collection有完全一样的接口,但是不同List,虽然Set就是Collection,但是行为不同,这就是多态和继承的应用了。

 

[java] view plain copy  print?

  1. public class TestSet {  
  2.     public static void main(String[] args) {  
  3.         Set<Integer> set = new HashSet<Integer>();  
  4.         Random r = new Random(400);  
  5.           
  6.         for(int i = 0;i<20;i++){  
  7.             set.add(r.nextInt(300));  
  8.         }  
  9.         System.out.println(set);  
  10.     }  
  11. }  


HashSet,没有重复元素,顺序也无规律,其实是使用了散列,以后会提到。

 

 

如果:

[java] view plain copy  print?

  1. Set<Integer> set = new TreeSet<Integer>();  

会发现是有序的,TreeSet将元素存储在了红黑树里面。

 

书中有一处错误:LinkedHashSet写成LinkedHashList了,它也使用散列,但是看起来使用了链表维护元素插入顺序。

 

 

 

11)Map

作者说将对象映射到其他对象的能力是解决编程问题的杀手锏。

确实,例如查看随机数的分布,如果真是随机数的话,那么10000次产生20以内的随机数,每个数字出现的次数应该是相近的。

 

[java] view plain copy  print?

  1. public class TestMap {  
  2.     public static void main(String[] args) {  
  3.         Map<Integer,Integer> map = new HashMap<Integer,Integer>();  
  4.         Random r = new Random(47);  
  5.           
  6.         //map里面为空  
  7.         System.out.println(map.get(1));  
  8.         for (int i = 0; i < 10000; i++) {  
  9.             int j = r.nextInt(10);  
  10.             Integer temp = map.get(j);  
  11.             map.put( j ,temp == null ? 1 : temp+1);  
  12.         }  
  13.         System.out.println(map);  
  14.     }  
  15. }  
  16.   
  17. //result:null  
  18. //{0=994, 1=1033, 2=1010, 3=1014, 4=958, 5=1000, 6=1052, 7=980, 8=946, 9=1013}  

 

数字确实是随机分布的,Map也很好用。

Map也用到多维。

 

[java] view plain copy  print?

  1. Map<Person,List<TV>>;  

 

 

12)Queue

先进先出,买基金的时候,由于后期追加购买,但是前期的基金已经满1个月,这样不用赎回费,然后问了客服之后发现,先买进的先赎回,然后自己大拍大腿,这不就是所谓的队列设计吗?

 

LinkedList实现了Queue接口。

对了,经常用到Random,竟然忘了说为什么作者传参用了47,其实Random传参是传入一个计算的种子,默认是系统时间,47在他看来一直是“魔幻数字”。

 

[java] view plain copy  print?

  1. public class TestQueue {  
  2.     public static void main(String[] args) {  
  3.         Queue<Integer> q  = new LinkedList<Integer>();  
  4.         Random r = new Random(47);  
  5.         for (int i = 0; i < 10; i++) {  
  6.         //将一个元素插入队尾  
  7.             q.offer(r.nextInt(12));  
  8.         }  
  9.         //返回队头  
  10.         System.out.println(q.peek());  
  11.         System.out.println(q);  
  12.     }  
  13. }  

 

 

 

一、PriorityQueue

直接看例子:

 

[java] view plain copy  print?

  1. public class TestPriorityQueue {  
  2.     public static void main(String[] args) {  
  3.         String s = "What 's your favorite number ,1 or 2?";  
  4.           List<String> l = Arrays.asList(s.split(""));  
  5.           PriorityQueue<String> pq = new PriorityQueue<String>(l);  
  6.   
  7.           while(pq.peek()!=null){  
  8.               System.out.print(pq.remove()+" ");  
  9.           }  
  10.     }  
  11. }  
  12.   
  13. result:  
  14. [,  ,  ,  ,  , b,  , 1,  , i, e, n, h, ',  , a, o, 2, ?, y, t, t, o, u, u, m, r, e,  
  15.  r, f, ,, s, a, v, r, o, W, r]                
  16.                  
  17.           ' , 1 2 ? W a a b e e f h i m n o o o r r r r s t t u u v y   

 

 

 

先级最高最先弹出,在优先队列里面 最小的值拥有最高的优先级,如果为String,从上面看,空格优先级最高。

直接输出并不会排序,这和我之前预想的不一样。

要顺序输出,需要用peek方法,返回队头,空返回null,然后remove的时候优先级高的会现出来。

 

[java] view plain copy  print?

  1.  public static void main(String[] args) {  
  2.         String s = "werwerwer";  
  3.         List<String> l = Arrays.asList(s.split(""));  
  4.         PriorityQueue<String> pq = new PriorityQueue<String>(l);  
  5.         while (pq.peek() != null) {  
  6.             System.out.print(pq.remove() + " ");  
  7.         }  
  8.         pq = new PriorityQueue<String>(l);  
  9.         System.out.println(pq.peek());  
  10.         pq.remove();  
  11.         System.out.println(pq.peek());  
  12.         pq.remove();  
  13.         System.out.println(pq.peek());  
  14.     }  
  15.   
  16. result:  
  17.  e e e r r r w w w   
  18. e  
  19. e  

 

 

 

结果让我奇怪的是String里面有空格。这个看了字符串再回来解决。

 

13)Foreach与迭代器

foreach遍历:

 

[java] view plain copy  print?

  1. public class Box {  
  2.     public static void main(String[] args) {  
  3.         Collection<String> c = new LinkedList<String>();  
  4.         String s = "you are so great";  
  5.         Collections.addAll(c,s.split(" "));  
  6.         for(String string : c){  
  7.             System.out.println(string);  
  8.         }  
  9.     }  
  10. }  

 

原来foreach是Java SE5引入的特性,因为同时也引入了Iterable接口,接口产生Iterator的Iterator方法,Iterable被Foreach用来在序列中移动。所以实现Iterable的接口的类都可以用于Foreach语句。

 

 

[java] view plain copy  print?

  1. All Known Subinterfaces:   
  2. BeanContext, BeanContextServices, BlockingDeque<E>, BlockingQueue<E>,   
  3. Collection<E>, Deque<E>, DirectoryStream<T>, List<E>, NavigableSet<E>,  
  4.  Queue<E>, Set<E>, SortedSet<E>   

 

其实Iterable的子接口有这么多,接下来实现Collection接口的自然也就实现了Iterable接口,所以也适用。

 

 

总结:

 

先看容器分类图:

点线为接口,实线为具体类,空心箭头指实现接口,实心箭头指某个类可以生成箭头所指向的类的对象。

 

1、数组可以存放对象,存放基本类型的数据,可以多维,就是容量不能改变。

 

2、Collection保存单一的元素,Map保存键值对。

 

3、List和数组类似,但是List可以自动扩充容量。大量随机访问使用ArrayList,经常进行插入删除操作,用LinkedList。

 

[java] view plain copy  print?

  1. public class Box {  
  2.     public static void main(String[] args) {  
  3.         long start = System.currentTimeMillis();  
  4.        Random r = new Random(47);  
  5.        LinkedList<Integer> l = new LinkedList<Integer>();  
  6.        for(int i = 0; i< 1000000; i++){  
  7.            l.add(r.nextInt(1000));  
  8.        }  
  9.        long end = System.currentTimeMillis();  
  10.        System.out.println(end - start);  
  11.          
  12.       ArrayList<Integer> a = new ArrayList<Integer>();  
  13.       for(int i = 0; i< 1000000; i++){  
  14.           a.add(r.nextInt(1000));  
  15.       }  
  16.       long end2 = System.currentTimeMillis();  
  17.       System.out.println(end2 -end);  
  18.     }  
  19. }  


4、Map,HashMap用来快速访问,TreeMap保持键的排序,速度没HashMap快,LinkedHashMap保持元素排序,也通过散列也能快速访问,于两者中间。

 

 

5、Set元素不重复,TreeSet,HashSet,LinkedHashSet与Map的类似。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值