渣渣小本求职复习之路每天一博客系列——Java基础(6)

  前情回顾:上一篇除了回顾了异常处理的后半部分之外,还进行了对Collection的初步了解,包括它的继承和实现架构以及各子类的特性以及用法。

  不知道大家有没有这样的经历,就是自己在寻求别人的帮助时,有时候会因为对方的没有痛快答应而感到恼火。自己私底下再想想,告诉自己别人真没有必须要帮助自己的义务,真不能对他们要求太多。想着想着,转而会觉得自己好没用,怎么就知道靠别人。就这样,被自尊和自卑不清不楚地折磨着。

  若是能够走出来倒是好。如果确定某些事情必须只能靠自己去完成,某些困难只能靠自己去克服,那就绝不要怨天尤人,责怪没人帮助自己。像日本动漫里面的热血主人公一样,在心里大喊一句:少年,勇敢起来, 冲吧!然后该做什么,就做什么,做完做好就对了。

————————————————————————闲聊结束—————————————————————————————

  第八章:Collection

  第五节:访问对象的Iterator

  其实,详细看过API说明文档Collection部分的童鞋都应该有印象。在Collection接口中,有定义一个方法,就是这一节的主题——iterator()方法会返回java.util.Iterator接口的实现对象,这个对象包括了Collection收集的所有对象。我们可以使用Iterator的hasNext()看看有无下一个对象,若有的话,再使用next()取得下一个对象。因此,无论List、Set、Queue还是任何Collection,都可以使用以下的forEach()来显示所收集的对象:

1 ...
2     private static void forEach(Collection collection){
3         Iterator iterator = collection.iterator();
4         while(iterator.hasNext()){
5             System.out.println(iterator.next());
6         }
7     }
8 ...

  任何实现了Iterable的对象,都可以使用整个forEach()方法,而不一定是Collection。

  第六节:对收集的对象进行排序

  相信学过数据结构与常用算法的童鞋都对几个排序算法比较熟悉,例如冒泡、归并、快排等。在java中,排序是常用的方法,不用我们亲自去实现。java.util.Collection就有提供sort()方法以供排序。要想排序,必须得有索引才行,因此Collection的sort()方法把实现List的对象作为参数。看到以下的示例代码:

 1 package cc.openhome;
 2 
 3 import java.util.*;
 4 
 5 public class Sort {
 6     public static void main(String[] args) {
 7         List numbers = Arrays.asList(10, 2, 3, 1, 9, 15, 4);
 8         Collections.sort(numbers);
 9         System.out.println(numbers);
10     }
11 }

  可是,如果是下面的例子,却会出现异常

 1 package cc.openhome;
 2 
 3 import java.util.*;
 4 
 5 class Account {
 6     private String name;
 7     private String number;
 8     private int balance;
 9 
10     Account(String name, String number, int balance) {
11         this.name = name;
12         this.number = number;
13         this.balance = balance;
14     }
15 
16     @Override
17     public String toString() {
18         return String.format("Account(%s, %s, %d)", name, number, balance);
19     }
20     
21 }
22 
23 public class Sort2 {
24     public static void main(String[] args) {
25         List accounts = Arrays.asList(
26                 new Account("Justin", "X1234", 1000),
27                 new Account("Monica", "X5678", 500),
28                 new Account("Irene", "X2468", 200)
29         );
30         Collections.sort(accounts);
31         System.out.println(accounts);
32     }
33 }

  异常如下截图:

  抛出这个异常,是因为我们的程序没有告诉sort()方法到底要根据Account的name、number或balance进行排序。Collections的sort()方法要求被排序的对象,必须实现java.lang.Comparable接口,这个接口有个compareTo()方法必须返回大于0、等于0或小于0的数。可是,这又有什么用呢?先看看下面的代码:

 1 package cc.openhome;
 2 
 3 import java.util.*;
 4 
 5 class Account2 implements Comparable {
 6     private String name;
 7     private String number;
 8     private int balance;
 9 
10     Account2(String name, String number, int balance) {
11         this.name = name;
12         this.number = number;
13         this.balance = balance;
14     }
15 
16     @Override
17     public String toString() {
18         return String.format("Account2(%s, %s, %d)", name, number, balance);
19     }
20 
21     @Override
22     public int compareTo(Object o) {
23         Account2 other = (Account2) o;
24         return this.balance - other.balance;
25     }
26 }
27 
28 public class Sort3 {
29     public static void main(String[] args) {
30         List accounts = Arrays.asList(
31                 new Account2("Justin", "X1234", 1000),
32                 new Account2("Monica", "X5678", 500),
33                 new Account2("Irene", "X2468", 200)
34         );
35         Collections.sort(accounts);
36         System.out.println(accounts);
37     }
38 }

  Collections的sort()方法在取得a对象与b对象进行比较时,会先将a对象扮演(Cast)为Comparable(也因此若对象没实现Comparable,将会抛出ClassCastException),然后调用a.compareTo(b),如果a对象顺序上小于b对象,必须返回小于0的值,若顺序上相等则返回0,若大于则返回大于0的值。为什么前面的Sort类中,可以直接对Integer进行排序呢?若查看API文档,我们就可以发现,Integer实现了Comparable接口。

  第七节:使用泛型

  Collection收集对象的时候,考虑到会收集各种对象,所以内部实现采用了Object参考收集的对象,所以执行时期被收集的对象会失去形态信息,也因此取回对象之后,必须自行记得对象的真正类型,并在语法上告诉编译程序让对象重新扮演为自己的类型。

  Collection虽然可以收集各种对象,但实际上通常只会收集同一种类型的对象,例如都是收集Integer对象。在JDK5之后,新增了泛型(Genertics)语法,让我们在设计API时可以指定类或方法支持泛型,而是用API的客户端在语法上会更为简洁,并得到编译时期检查。加入泛型语法的ArrayList示范:

 1 package cc.openhome;
 2 
 3 import java.util.Arrays;
 4 
 5 public class ArrayList<E> {
 6     private Object[] list;
 7     private int next;
 8    
 9     public ArrayList(int capacity) {
10         list = new Object[capacity];
11     }
12 
13     public ArrayList() {
14         this(16);
15     }
16 
17     public void add(E e) {
18         if(next == list.length) {
19             list = Arrays.copyOf(list, list.length * 2);
20         }
21         list[next++] = e;
22     }
23     
24     public E get(int index) {
25         return (E) list[index];
26     }
27     
28     public int size() {
29         return next;
30     }
31 }

  注意到类名称盘的角括号<E>,这表示这个类支持泛型。实际加入ArrayList的对象会是客户端声明的E类型。当然了,E(Element)只是一个类型代号,我们可以用A~Z都行。由于使用<E>定义类型,在需要编译程序检查类型的地方,都可以使用E,例如add()方法必须检查传入的对象类型是E,get()方法必须转换为E类型。

 

  Collection就进行到这里了。更多的内容,尤其是关于泛型的语法细节,我们会在后面的博客中介绍。

 

  第九章:键-值对应的Map

  根据某个键(Key)来取得对应的值(Value),我们可以用实现java.util.Map接口的类对象来建立键值对应数据。建立之后,如果要取得值,只要用对应的键就可以迅速取得。

  第一节:Map设计架构

  先了解一下Map设计架构,对正确使用API帮助相当大,至少不会稀里糊涂。

  

  常用的Map实现类有java.util.HashMap与java.util.TreeMap,都继承了抽象类java.util.AbstractMap。至于Dictionary和HashTable是JDK1.0遗留下来的API,不被建议使用,但是图上没有的java.util.Properties是HashTable的子类,却是挺常用的。

  第二节:HashMap

  Map支持上一章最后提到的泛型语法,我们先直接来看一个范例,可以根据用户名称取得对应的信息:

 1 package cc.openhome;
 2 
 3 import java.util.*;
 4 
 5 public class Messages {
 6     public static void main(String[] args) {
 7         Map<String, String> messages = new HashMap<>();   //以泛型语法指定键值类型
 8         messages.put("Justin", "Hello!Justin的信息!");  //建立键值对应
 9         messages.put("Monica", "给Monica的悄悄话!");
10         messages.put("Irene", "Irene的可爱猫喵喵叫!");
11         
12         Scanner scanner = new Scanner(System.in);
13         System.out.print("取得谁的信息:");
14         String message = messages.get(scanner.nextLine()); //根据键取回值
15         System.out.println(message);
16         System.out.println(messages);
17     }
18 }

  建立Map实现对象的时候,可以使用泛型语法来指定键-值的类型。在这里键使用String,值也使用String类型。要建立键值对应,可以使用put()方法,第一个自变量是键,第二个变量是值。键,是不会重复的。如果要指定键取回对应的值,则使用get()方法。那么,大家知不知道,如果我们指定的键不存在,会有什么样的结果呢?这次先不看API文档,来一段源代码好了。

 

 1     public V get(Object key) {
 2         if (key == null)
 3             return getForNullKey();
 4         int hash = hash(key.hashCode());
 5         for (Entry<K,V> e = table[indexFor(hash, table.length)];
 6              e != null;
 7              e = e.next) {
 8             Object k;
 9             if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
10                 return e.value;
11         }
12         return null;
13     }

 

  根据这个get方法,我们很明显能看到,如果我们的key等于null,那么就会返回getForNullKey()的结果,如果key不为null也不在HashMap里,那就会返回null。(哈哈,这算是我第一次看JDK的源代码吧)。那getForNullKey()的结果是什么呢?其实Key的可以设为null,如果我们有一个键的值为null,get()方法就会返回键对应的值,如果不存在,则还是会返回null。

  第三节:TreeMap

  在HashMap中建立键值对应之后,键是无序的。如果想排序,我们可以用TreeMap。不过条件是作为键盘的对象必须实现Compareable接口,或者是在创建TreeMap时指定实现Comparable接口的对象。例如下面这个范例:

 1 package cc.openhome;
 2 
 3 import java.util.*;
 4 
 5 public class Messages2 {
 6     public static void main(String[] args) {
 7         Map<String, String> messages = new TreeMap<>(); 
 8         messages.put("Justin", "Hello!Justin的信息!");
 9         messages.put("Monica", "给Monica的悄悄话!");
10         messages.put("Irene", "Irene的可爱猫喵喵叫!");
11         System.out.println(messages);
12     }
13 }

 

  由于String实现了Comparable接口,因此我们可以看到结果是排序的。(截图就不贴出来了,大家去试试吧。)

  第四节:访问键值

  有的时候,我们可能需要取得Map中所有的值,或者是想取得Map中所有的值。Map虽然跟Collection没有继承上的关系,然而却是彼此配合的API。

  如果想要取得Map中所有的键,可以调用Map的keySet()返回Set对象。由于键是不重复的,所以用Set返回是当然的;如果想要取得Map中所有的值,则可以使用values()返回Collection对象。看下面这段代码:

 

 1 package cc.openhome;
 2 
 3 import java.util.*;
 4 
 5 public class MapKeyValue {
 6     public static void main(String[] args) {
 7         Map<String, String> map = new HashMap<>();
 8         map.put("one", "一");
 9         map.put("two", "二");
10         map.put("three", "三");
11         
12         System.out.println("显示键");
13         foreach(map.keySet());
14         
15         System.out.println("显示值");
16         foreach(map.values());
17     }
18     
19     public static void foreach(Iterable<String> iterable) {
20         for(String element : iterable) {
21             System.out.println(element);
22         }
23     }
24 }

 

  或者说,想要同时取得Map的键和值,我们可以使用entrySet()方法,这会返回一个Set对象,每个元素都是Map.Entry实例,可以调用getKey()取得键,调用getValue()取得值。看下面这段代码:

 1 package cc.openhome;
 2 
 3 import java.util.*;
 4 
 5 public class MapKeyValue2 {
 6     public static void main(String[] args) {
 7         Map<String, String> map = new TreeMap<>();
 8         map.put("one", "一");
 9         map.put("two", "二");
10         map.put("three", "三");
11         foreach(map.entrySet());
12     }
13     
14     public static void foreach(Iterable<Map.Entry<String, String>> iterable) {
15         for(Map.Entry<String, String> entry: iterable) {
16             System.out.printf("(键 %s, 值 %s)%n", 
17                     entry.getKey(), entry.getValue());
18         }
19     }
20 }

 

——————————————————————————第二十天——————————————————————————

  紧赶慢赶,终于赶完了。

1.今早妈妈给我打了个电话。我跟她说了我最近的情况。希望她能够明白,我最近过得很好,没有浪费大学仅剩不多的时间。

2.关于误会,恐怕只有理解和沟通才能解开。就怕赌气,就怕错过能够解开的时机。

3.昨晚还算有点怨气,到现在下午就已经慢慢没什么感觉了。我给自己最好的生日礼物就是,按照我希望的那样成长起来。

posted @ 2013-11-07 19:03  LevenYes  阅读(339)  评论(2编辑  收藏  举报