- 浏览: 43871 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
imGaofy:
谢谢, 解惑
JAVA中mark()和reset()用法 -
雪飞鹄:
我也在做,大哥有没有例子呀,我刚学的gis不太懂,能发我下吗0 ...
openscales 画圆(原创) -
zhyy22145:
学习
Array.prototype.slice.call(arguments,0) -
liuhuoxingkong:
请问有没有源代码啊?或者详细一点,用的是openscales中 ...
openscales 画圆(原创)
今天在网上搜索了一下,发现一篇关于java集合的博文,里面整理得非常好, 特意copy过来和大家分享一下
本讲内容:集合 collection
讲集合collection之前,我们先分清三个概念:
colection 集合,用来表示任何一种数据结构
Collection 集合接口,指的是 java.util.Collection接口,是 Set、List 和 Queue 接口的超类接口
Collections 集合工具类,指的是 java.util.Collections 类。
SCJP考试要求了解的接口有:Collection , Set , SortedSet , List , Map , SortedMap , Queue , NavigableSet , NavigableMap, 还有一个 Iterator 接口也是必须了解的。
SCJP考试要求了解的类有: HashMap , Hashtable ,TreeMap , LinkedHashMap , HashSet , LinkedHashSet ,TreeSet , ArrayList , Vector , LinkedList , PriorityQueuee , Collections , Arrays
下面给出一个集合之间的关系图:
上图中加粗线的ArrayList 和 HashMap 是我们重点讲解的对象。下面这张图看起来层级结构更清晰些。
我们这里说的集合指的是小写的collection,集合有4种基本形式,其中前三种的父接口是Collection。
List 关注事物的索引列表
Set 关注事物的唯一性
Queue 关注事物被处理时的顺序
Map 关注事物的映射和键值的唯一性
一、Collection 接口
Collection接口是 Set 、List 和 Queue 接口的父接口,提供了多数集合常用的方法声明,包括 add()、remove()、contains() 、size() 、iterator() 等。
add(E e) 将指定对象添加到集合中
remove(Object o) 将指定的对象从集合中移除,移除成功返回true,不成功返回false
contains(Object o) 查看该集合中是否包含指定的对象,包含返回true,不包含返回flase
size() 返回集合中存放的对象的个数。返回值为int
clear() 移除该集合中的所有对象,清空该集合。
iterator() 返回一个包含所有对象的iterator对象,用来循环遍历
toArray() 返回一个包含所有对象的数组,类型是Object
toArray(T[] t) 返回一个包含所有对象的指定类型的数组
我们在这里只举一个把集合转成数组的例子,因为Collection本身是个接口所以,我们用它的实现类ArrayList做这个例子:
view source
print
?
01 import java.util.ArrayList;
02 import java.util.Collection;
03
04 public class CollectionTest {
05
06 public static void main(String[] args) {
07
08 String a = "a",b="b",c="c";
09 Collection list = new ArrayList();
10 list.add(a);
11 list.add(b);
12 list.add(c);
13
14 String[] array = list.toArray(new String[1]);
15
16 for(String s : array){
17 System.out.println(s);
18 }
19 }
20 }
编译并运行程序,检查结果:
二、几个比较重要的接口和类简介
1、List接口
List 关心的是索引,与其他集合相比,List特有的就是和索引相关的一些方法:get(int index) 、 add(int index,Object o) 、 indexOf(Object o) 。
ArrayList 可以将它理解成一个可增长的数组,它提供快速迭代和快速随机访问的能力。
LinkedList 中的元素之间是双链接的,当需要快速插入和删除时LinkedList成为List中的不二选择。
Vector 是ArrayList的线程安全版本,性能比ArrayList要低,现在已经很少使用
2、Set接口
Set关心唯一性,它不允许重复。
HashSet 当不希望集合中有重复值,并且不关心元素之间的顺序时可以使用此类。
LinkedHashset 当不希望集合中有重复值,并且希望按照元素的插入顺序进行迭代遍历时可采用此类。
TreeSet 当不希望集合中有重复值,并且希望按照元素的自然顺序进行排序时可以采用此类。(自然顺序意思是某种和插入顺序无关,而是和元素本身的内容和特质有关的排序方式,譬如“abc”排在“abd”前面。)
3、Queue接口
Queue用于保存将要执行的任务列表。
LinkedList 同样实现了Queue接口,可以实现先进先出的队列。
PriorityQueue 用来创建自然排序的优先级队列。番外篇中有个例子http://android.yaohuiji.com/archives/3454你可以看一下。
4、Map接口
Map关心的是唯一的标识符。他将唯一的键映射到某个元素。当然键和值都是对象。
HashMap 当需要键值对表示,又不关心顺序时可采用HashMap。
Hashtable 注意Hashtable中的t是小写的,它是HashMap的线程安全版本,现在已经很少使用。
LinkedHashMap 当需要键值对,并且关心插入顺序时可采用它。
TreeMap 当需要键值对,并关心元素的自然排序时可采用它。
三、ArrayList的使用
ArrayList是一个可变长的数组实现,读取效率很高,是最常用的集合类型。
1、ArrayList的创建
在Java5版本之前我们使用:
view source
print
?
1 List list = new ArrayList();
在Java5版本之后,我们使用带泛型的写法:
view source
print
?
1 List<String> list = new ArrayList<String>();
上面的代码定义了一个只允许保存字符串的列表,尖括号括住的类型就是参数类型,也成泛型。带泛型的写法给了我们一个类型安全的集合。关于泛型的知识可以参见这里。
2、ArrayList的使用:
view source
print
?
01 List<String> list = new ArrayList<String>();
02 list.add("nihao!");
03 list.add("hi!");
04 list.add("konikiwa!");
05 list.add("hola");
06 list.add("Bonjour");
07 System.out.println(list.size());
08 System.out.println(list.contains(21));
09 System.out.println(list.remove("hi!"));
10 System.out.println(list.size());
关于List接口中的方法和ArrayList中的方法,大家可以看看JDK中的帮助。
3、基本数据类型的的自动装箱:
我们知道集合中存放的是对象,而不能是基本数据类型,在Java5之后可以使用自动装箱功能,更方便的导入基本数据类型。
view source
print
?
1 List<Integer> list = new ArrayList<Integer>();
2 list.add(new Integer(42));
3 list.add(43);
4、ArrayList的排序:
ArrayList本身不具备排序能力,但是我们可以使用Collections类的sort方法使其排序。我们看一个例子:
view source
print
?
01 import java.util.ArrayList;
02 import java.util.Collections;
03 import java.util.List;
04
05 public class Test {
06
07 public static void main(String[] args) {
08 List<String> list = new ArrayList<String>();
09 list.add("nihao!");
10 list.add("hi!");
11 list.add("konikiwa!");
12 list.add("hola");
13 list.add("Bonjour");
14
15 System.out.println("排序前:"+ list);
16
17 Collections.sort(list);
18
19 System.out.println("排序后:"+ list);
20 }
21
22 }
编译并运行程序查看结果:
排序前:[nihao!, hi!, konikiwa!, hola, Bonjour]
排序后:[Bonjour, hi!, hola, konikiwa!, nihao!]
5、数组和List之间的转换
从数组转换成list,可以使用Arrays类的asList()方法:
view source
print
?
01 import java.util.ArrayList;
02 import java.util.Collections;
03 import java.util.List;
04
05 public class Test {
06
07 public static void main(String[] args) {
08
09 String[] sa = {"one","two","three","four"};
10 List list = Arrays.asList(sa);
11 System.out.println("list:"+list);
12 System.out.println("list.size()="+list.size());
13 }
14
15 }
6、Iterator和for-each
在for-each出现之前,我们想遍历ArrayList中的每个元素我们会使用Iterator接口:
view source
print
?
01 import java.util.Arrays;
02 import java.util.Iterator;
03 import java.util.List;
04
05 public class Test {
06
07 public static void main(String[] args) {
08
09 // Arrays类为我们提供了一种list的便捷创建方式
10 List<String> list = Arrays.asList("one", "two", "three", "four");
11
12 // 转换成Iterator实例
13 Iterator<String> it = list.iterator();
14
15 //遍历
16 while (it.hasNext()) {
17 System.out.println(it.next());
18 }
19
20 }
21
22 }
在for-each出现之后,遍历变得简单一些:
01 import java.util.Arrays;
02 import java.util.Iterator;
03 import java.util.List;
04
05 public class Test {
06
07 public static void main(String[] args) {
08
09 // Arrays类为我们提供了一种list的便捷创建方式
10 List<String> list = Arrays.asList("one", "two", "three", "four");
11
12 for (String s : list) {
13 System.out.println(s);
14 }
15
16 }
17
18 }
本讲内容:Map HashMap
前面课程中我们知道Map是个接口,它关心的是映射关系,它里面的元素是成对出现的,键和值都是对象且键必须保持唯一。这一点上看它和Collection是很不相同的。
一、Map接口
Map接口的常用方法如下表所示:
put(K key, V value) 向集合中添加指定的键值对
putAll(Map <? extends K,? extends V> t) 把一个Map中的所有键值对添加到该集合
containsKey(Object key) 如果包含该键,则返回true
containsValue(Object value) 如果包含该值,则返回true
get(Object key) 根据键,返回相应的值对象
keySet() 将该集合中的所有键以Set集合形式返回
values() 将该集合中所有的值以Collection形式返回
remove(Object key) 如果存在指定的键,则移除该键值对,返回键所对应的值,如果不存在则返回null
clear() 移除Map中的所有键值对,或者说就是清空集合
isEmpty() 查看Map中是否存在键值对
size() 查看集合中包含键值对的个数,返回int类型
因为Map中的键必须是唯一的,所以虽然键可以是null,只能由一个键是null,而Map中的值可没有这种限制,值为null的情况经常出现, 因此get(Object key)方法返回null,有两种情况一种是确实不存在该键值对,二是该键对应的值对象为null。为了确保某Map中确实有某个键,应该使用的方法是 containsKey(Object key) 。
二、HashMap
HashMap是最常用的Map集合,它的键值对在存储时要根据键的哈希码来确定值放在哪里。
1、HashMap的基本使用:
view source
print
?
01 import java.util.Collection;
02 import java.util.HashMap;
03 import java.util.Map;
04 import java.util.Set;
05
06 public class Test {
07
08 public static void main(String[] args) {
09
10 Map<Integer,String> map = new HashMap<Integer,String>();
11
12 map.put(1, "白菜");
13 map.put(2, "萝卜");
14 map.put(3, "茄子");
15 map.put(4, null);
16 map.put(null, null);
17 map.put(null, null);
18
19 System.out.println("map.size()="+map.size());
20 System.out.println("map.containsKey(1)="+map.containsKey(2));
21 System.out.println("map.containsKey(null)="+map.containsKey(null));
22 System.out.println("map.get(null)="+map.get(null));
23
24 System.out.println("map.get(2)="+map.get(2));
25 map.put(null, "黄瓜");
26 System.out.println("map.get(null)="+map.get(null));
27
28 Set set = map.keySet();
29 System.out.println("set="+set);
30
31 Collection<String> c = map.values();
32
33 System.out.println("Collection="+c);
34
35 }
36
37 }
编译并运行程序,查看结果:
view source
print
?
1 map.size()=5
2 map.containsKey(1)=true
3 map.containsKey(null)=true
4 map.get(null)=null
5 map.get(2)=萝卜
6 map.get(null)=黄瓜
7 set=[null, 1, 2, 3, 4]
8 Collection=[黄瓜, 白菜, 萝卜, 茄子, null]
2、HashMap 中作为键的对象必须重写Object的hashCode()方法和equals()方法
下面看一个我花了1个小时构思的例子,熟悉龙枪的朋友看起来会比较亲切,设定了龙和龙的巢穴,然后把它们用Map集合对应起来,我们可以根据龙查看它巢穴中的宝藏数量,例子只是为了说明hashCode这个知识点,所以未必有太强的故事性和合理性,凑合看吧:
view source
print
?
01 import java.util.HashMap;
02 import java.util.Map;
03
04 public class Test {
05
06 public static void main(String[] args) {
07
08 // 龙和它的巢穴映射表
09 Map<dragon , Nest> map = new HashMap<dragon , Nest>();
10
11 // 在Map中放入四只克莱恩大陆上的龙
12 map.put(new Dragon("锐刃", 98), new Nest(98));
13 map.put(new Dragon("明镜", 95), new Nest(95));
14 map.put(new Dragon("碧雷", 176), new Nest(176));
15 map.put(new Dragon("玛烈", 255), new Nest(255));
16
17 // 查看宝藏
18 System.out.println("碧雷巢穴中有多少宝藏:" + map.get(new Dragon("碧雷", 176)).getTreasure());
19 }
20
21 }
22
23 // 龙
24 class Dragon {
25
26 Dragon(String name, int level) {
27 this.level = level;
28 this.name = name;
29 }
30
31 // 龙的名字
32 private String name;
33
34 // 龙的级别
35 private int level;
36
37 public int getLevel() {
38 return level;
39 }
40
41 public void setLevel(int level) {
42 this.level = level;
43 }
44
45 public String getName() {
46 return name;
47 }
48
49 public void setName(String name) {
50 this.name = name;
51 }
52
53 }
54
55 // 巢穴
56 class Nest {
57
58 //我研究的龙之常数
59 final int DRAGON_M = 4162;
60
61 // 宝藏
62 private int treasure;
63
64 // 居住的龙的级别
65 private int level;
66
67 Nest(int level) {
68 this.level = level;
69 this.treasure = level * level * DRAGON_M;
70 }
71
72 int getTreasure() {
73 return treasure;
74 }
75
76 public int getLevel() {
77 return level;
78 }
79
80 public void setLevel(int level) {
81 this.level = level;
82 this.treasure = level * level * DRAGON_M;
83 }
84
85 }
编译并运行查看结果:
view source
print
?
1 Exception in thread "main" java.lang.NullPointerException
2 at Test.main(Test.java:18)
我们发现竟然报了错误,第18行出了空指针错误,也就是说get方法竟然没有拿到预期的巢穴对象。
在这里我们就要研究一下为什么取不到了。我们这里先解释一下HashMap的工作方式。
假设现在有个6张中奖彩票的存根,放在5个桶里(彩票首位只有1-5,首位是1的就放在一号桶,是2的就放在2号桶,依次类推),现在你拿了3张彩 票来兑奖,一个号码是113,一个号码是213,一个号码是313。那么现在先兑第一张,取出一号桶里的存根发现存根号码和你的号码不符,所以你第一张没 中奖。继续兑第二张,二号桶里就没存根所以就直接放弃了,把三号桶里的所有彩票存根都拿出来对应一番,最后发现有一个存根恰好是313,那么恭喜你中奖 了。
HashMap在确定一个键对象和另一个键对象是否是相同时用了同样的方法,每个桶就是一个键对象的散列码值,桶里放的就是散列码相同的彩票存根, 如果散列码不同,那么肯定没有相关元素存在,如果散列码相同,那么还要用键的equals()方法去比较是否相同,如果相同才认为是相同的键。简单的说就 是 hashCode()相同 && equals()==true 时才算两者相同。
到了这里我们应该明白了,在没有重写一个对象的hashcode()和equals()方法之前,它们执行的是Object中对应的方法。而 Object的hashcode()是用对象在内存中存放的位置计算出来的,每个对象实例都不相同。Object的equals()的实现更简单就是看两 个对象是否==,也就是两个对象除非是同一个对象,否则根本不会相同。因此上面的例子虽然都是名字叫碧雷的龙,但是HashMap中却无法认可它们是相同 的。
因此我们只有重写Key对象的hashCode()和equals()方法,才能避免这种情形出现,好在Eclipse可以帮我们自动生成一个类的hashCode()和equals(),我们把上面的例子加上这两个方法再试试看:
view source
print
?
001 import java.util.HashMap;
002 import java.util.Map;
003
004 public class Test {
005
006 public static void main(String[] args) {
007
008 // 龙和它的巢穴映射表
009 Map<dragon , Nest> map = new HashMap<dragon , Nest>();
010
011 // 在Map中放入四只克莱恩大陆上的龙
012 map.put(new Dragon("锐刃", 98), new Nest(98));
013 map.put(new Dragon("明镜", 95), new Nest(95));
014 map.put(new Dragon("碧雷", 176), new Nest(176));
015 map.put(new Dragon("玛烈", 255), new Nest(255));
016
017 // 查看宝藏
018 System.out.println("碧雷巢穴中有多少宝藏:" + map.get(new Dragon("碧雷", 176)).getTreasure());
019 }
020
021 }
022
023 // 龙
024 class Dragon {
025
026 Dragon(String name, int level) {
027 this.level = level;
028 this.name = name;
029 }
030
031 // 龙的名字
032 private String name;
033
034 // 龙的级别
035 private int level;
036
037 public int getLevel() {
038 return level;
039 }
040
041 public void setLevel(int level) {
042 this.level = level;
043 }
044
045 public String getName() {
046 return name;
047 }
048
049 public void setName(String name) {
050 this.name = name;
051 }
052
053 @Override
054 public int hashCode() {
055 final int PRIME = 31;
056 int result = 1;
057 result = PRIME * result + level;
058 result = PRIME * result + ((name == null) ? 0 : name.hashCode());
059 return result;
060 }
061
062 @Override
063 public boolean equals(Object obj) {
064 if (this == obj)
065 return true;
066 if (obj == null)
067 return false;
068 if (getClass() != obj.getClass())
069 return false;
070 final Dragon other = (Dragon) obj;
071 if (level != other.level)
072 return false;
073 if (name == null) {
074 if (other.name != null)
075 return false;
076 } else if (!name.equals(other.name))
077 return false;
078 return true;
079 }
080
081 }
082
083 // 巢穴
084 class Nest {
085
086 //我研究的龙之常数
087 final int DRAGON_M = 4162;
088
089 // 宝藏
090 private int treasure;
091
092 // 居住的龙的级别
093 private int level;
094
095 Nest(int level) {
096 this.level = level;
097 this.treasure = level * level * DRAGON_M;
098 }
099
100 int getTreasure() {
101 return treasure;
102 }
103
104 public int getLevel() {
105 return level;
106 }
107
108 public void setLevel(int level) {
109 this.level = level;
110 this.treasure = level * level * DRAGON_M;
111 }
112
113 }
编译并运行查看结果:
view source
print
?
1 碧雷巢穴中有多少宝藏:128922112
这一次正常输出了,真不容易^_^
好了本讲就到这里。
本讲内容:集合 collection
讲集合collection之前,我们先分清三个概念:
colection 集合,用来表示任何一种数据结构
Collection 集合接口,指的是 java.util.Collection接口,是 Set、List 和 Queue 接口的超类接口
Collections 集合工具类,指的是 java.util.Collections 类。
SCJP考试要求了解的接口有:Collection , Set , SortedSet , List , Map , SortedMap , Queue , NavigableSet , NavigableMap, 还有一个 Iterator 接口也是必须了解的。
SCJP考试要求了解的类有: HashMap , Hashtable ,TreeMap , LinkedHashMap , HashSet , LinkedHashSet ,TreeSet , ArrayList , Vector , LinkedList , PriorityQueuee , Collections , Arrays
下面给出一个集合之间的关系图:
上图中加粗线的ArrayList 和 HashMap 是我们重点讲解的对象。下面这张图看起来层级结构更清晰些。
我们这里说的集合指的是小写的collection,集合有4种基本形式,其中前三种的父接口是Collection。
List 关注事物的索引列表
Set 关注事物的唯一性
Queue 关注事物被处理时的顺序
Map 关注事物的映射和键值的唯一性
一、Collection 接口
Collection接口是 Set 、List 和 Queue 接口的父接口,提供了多数集合常用的方法声明,包括 add()、remove()、contains() 、size() 、iterator() 等。
add(E e) 将指定对象添加到集合中
remove(Object o) 将指定的对象从集合中移除,移除成功返回true,不成功返回false
contains(Object o) 查看该集合中是否包含指定的对象,包含返回true,不包含返回flase
size() 返回集合中存放的对象的个数。返回值为int
clear() 移除该集合中的所有对象,清空该集合。
iterator() 返回一个包含所有对象的iterator对象,用来循环遍历
toArray() 返回一个包含所有对象的数组,类型是Object
toArray(T[] t) 返回一个包含所有对象的指定类型的数组
我们在这里只举一个把集合转成数组的例子,因为Collection本身是个接口所以,我们用它的实现类ArrayList做这个例子:
view source
?
01 import java.util.ArrayList;
02 import java.util.Collection;
03
04 public class CollectionTest {
05
06 public static void main(String[] args) {
07
08 String a = "a",b="b",c="c";
09 Collection list = new ArrayList();
10 list.add(a);
11 list.add(b);
12 list.add(c);
13
14 String[] array = list.toArray(new String[1]);
15
16 for(String s : array){
17 System.out.println(s);
18 }
19 }
20 }
编译并运行程序,检查结果:
二、几个比较重要的接口和类简介
1、List接口
List 关心的是索引,与其他集合相比,List特有的就是和索引相关的一些方法:get(int index) 、 add(int index,Object o) 、 indexOf(Object o) 。
ArrayList 可以将它理解成一个可增长的数组,它提供快速迭代和快速随机访问的能力。
LinkedList 中的元素之间是双链接的,当需要快速插入和删除时LinkedList成为List中的不二选择。
Vector 是ArrayList的线程安全版本,性能比ArrayList要低,现在已经很少使用
2、Set接口
Set关心唯一性,它不允许重复。
HashSet 当不希望集合中有重复值,并且不关心元素之间的顺序时可以使用此类。
LinkedHashset 当不希望集合中有重复值,并且希望按照元素的插入顺序进行迭代遍历时可采用此类。
TreeSet 当不希望集合中有重复值,并且希望按照元素的自然顺序进行排序时可以采用此类。(自然顺序意思是某种和插入顺序无关,而是和元素本身的内容和特质有关的排序方式,譬如“abc”排在“abd”前面。)
3、Queue接口
Queue用于保存将要执行的任务列表。
LinkedList 同样实现了Queue接口,可以实现先进先出的队列。
PriorityQueue 用来创建自然排序的优先级队列。番外篇中有个例子http://android.yaohuiji.com/archives/3454你可以看一下。
4、Map接口
Map关心的是唯一的标识符。他将唯一的键映射到某个元素。当然键和值都是对象。
HashMap 当需要键值对表示,又不关心顺序时可采用HashMap。
Hashtable 注意Hashtable中的t是小写的,它是HashMap的线程安全版本,现在已经很少使用。
LinkedHashMap 当需要键值对,并且关心插入顺序时可采用它。
TreeMap 当需要键值对,并关心元素的自然排序时可采用它。
三、ArrayList的使用
ArrayList是一个可变长的数组实现,读取效率很高,是最常用的集合类型。
1、ArrayList的创建
在Java5版本之前我们使用:
view source
?
1 List list = new ArrayList();
在Java5版本之后,我们使用带泛型的写法:
view source
?
1 List<String> list = new ArrayList<String>();
上面的代码定义了一个只允许保存字符串的列表,尖括号括住的类型就是参数类型,也成泛型。带泛型的写法给了我们一个类型安全的集合。关于泛型的知识可以参见这里。
2、ArrayList的使用:
view source
?
01 List<String> list = new ArrayList<String>();
02 list.add("nihao!");
03 list.add("hi!");
04 list.add("konikiwa!");
05 list.add("hola");
06 list.add("Bonjour");
07 System.out.println(list.size());
08 System.out.println(list.contains(21));
09 System.out.println(list.remove("hi!"));
10 System.out.println(list.size());
关于List接口中的方法和ArrayList中的方法,大家可以看看JDK中的帮助。
3、基本数据类型的的自动装箱:
我们知道集合中存放的是对象,而不能是基本数据类型,在Java5之后可以使用自动装箱功能,更方便的导入基本数据类型。
view source
?
1 List<Integer> list = new ArrayList<Integer>();
2 list.add(new Integer(42));
3 list.add(43);
4、ArrayList的排序:
ArrayList本身不具备排序能力,但是我们可以使用Collections类的sort方法使其排序。我们看一个例子:
view source
?
01 import java.util.ArrayList;
02 import java.util.Collections;
03 import java.util.List;
04
05 public class Test {
06
07 public static void main(String[] args) {
08 List<String> list = new ArrayList<String>();
09 list.add("nihao!");
10 list.add("hi!");
11 list.add("konikiwa!");
12 list.add("hola");
13 list.add("Bonjour");
14
15 System.out.println("排序前:"+ list);
16
17 Collections.sort(list);
18
19 System.out.println("排序后:"+ list);
20 }
21
22 }
编译并运行程序查看结果:
排序前:[nihao!, hi!, konikiwa!, hola, Bonjour]
排序后:[Bonjour, hi!, hola, konikiwa!, nihao!]
5、数组和List之间的转换
从数组转换成list,可以使用Arrays类的asList()方法:
view source
?
01 import java.util.ArrayList;
02 import java.util.Collections;
03 import java.util.List;
04
05 public class Test {
06
07 public static void main(String[] args) {
08
09 String[] sa = {"one","two","three","four"};
10 List list = Arrays.asList(sa);
11 System.out.println("list:"+list);
12 System.out.println("list.size()="+list.size());
13 }
14
15 }
6、Iterator和for-each
在for-each出现之前,我们想遍历ArrayList中的每个元素我们会使用Iterator接口:
view source
?
01 import java.util.Arrays;
02 import java.util.Iterator;
03 import java.util.List;
04
05 public class Test {
06
07 public static void main(String[] args) {
08
09 // Arrays类为我们提供了一种list的便捷创建方式
10 List<String> list = Arrays.asList("one", "two", "three", "four");
11
12 // 转换成Iterator实例
13 Iterator<String> it = list.iterator();
14
15 //遍历
16 while (it.hasNext()) {
17 System.out.println(it.next());
18 }
19
20 }
21
22 }
在for-each出现之后,遍历变得简单一些:
01 import java.util.Arrays;
02 import java.util.Iterator;
03 import java.util.List;
04
05 public class Test {
06
07 public static void main(String[] args) {
08
09 // Arrays类为我们提供了一种list的便捷创建方式
10 List<String> list = Arrays.asList("one", "two", "three", "four");
11
12 for (String s : list) {
13 System.out.println(s);
14 }
15
16 }
17
18 }
本讲内容:Map HashMap
前面课程中我们知道Map是个接口,它关心的是映射关系,它里面的元素是成对出现的,键和值都是对象且键必须保持唯一。这一点上看它和Collection是很不相同的。
一、Map接口
Map接口的常用方法如下表所示:
put(K key, V value) 向集合中添加指定的键值对
putAll(Map <? extends K,? extends V> t) 把一个Map中的所有键值对添加到该集合
containsKey(Object key) 如果包含该键,则返回true
containsValue(Object value) 如果包含该值,则返回true
get(Object key) 根据键,返回相应的值对象
keySet() 将该集合中的所有键以Set集合形式返回
values() 将该集合中所有的值以Collection形式返回
remove(Object key) 如果存在指定的键,则移除该键值对,返回键所对应的值,如果不存在则返回null
clear() 移除Map中的所有键值对,或者说就是清空集合
isEmpty() 查看Map中是否存在键值对
size() 查看集合中包含键值对的个数,返回int类型
因为Map中的键必须是唯一的,所以虽然键可以是null,只能由一个键是null,而Map中的值可没有这种限制,值为null的情况经常出现, 因此get(Object key)方法返回null,有两种情况一种是确实不存在该键值对,二是该键对应的值对象为null。为了确保某Map中确实有某个键,应该使用的方法是 containsKey(Object key) 。
二、HashMap
HashMap是最常用的Map集合,它的键值对在存储时要根据键的哈希码来确定值放在哪里。
1、HashMap的基本使用:
view source
?
01 import java.util.Collection;
02 import java.util.HashMap;
03 import java.util.Map;
04 import java.util.Set;
05
06 public class Test {
07
08 public static void main(String[] args) {
09
10 Map<Integer,String> map = new HashMap<Integer,String>();
11
12 map.put(1, "白菜");
13 map.put(2, "萝卜");
14 map.put(3, "茄子");
15 map.put(4, null);
16 map.put(null, null);
17 map.put(null, null);
18
19 System.out.println("map.size()="+map.size());
20 System.out.println("map.containsKey(1)="+map.containsKey(2));
21 System.out.println("map.containsKey(null)="+map.containsKey(null));
22 System.out.println("map.get(null)="+map.get(null));
23
24 System.out.println("map.get(2)="+map.get(2));
25 map.put(null, "黄瓜");
26 System.out.println("map.get(null)="+map.get(null));
27
28 Set set = map.keySet();
29 System.out.println("set="+set);
30
31 Collection<String> c = map.values();
32
33 System.out.println("Collection="+c);
34
35 }
36
37 }
编译并运行程序,查看结果:
view source
?
1 map.size()=5
2 map.containsKey(1)=true
3 map.containsKey(null)=true
4 map.get(null)=null
5 map.get(2)=萝卜
6 map.get(null)=黄瓜
7 set=[null, 1, 2, 3, 4]
8 Collection=[黄瓜, 白菜, 萝卜, 茄子, null]
2、HashMap 中作为键的对象必须重写Object的hashCode()方法和equals()方法
下面看一个我花了1个小时构思的例子,熟悉龙枪的朋友看起来会比较亲切,设定了龙和龙的巢穴,然后把它们用Map集合对应起来,我们可以根据龙查看它巢穴中的宝藏数量,例子只是为了说明hashCode这个知识点,所以未必有太强的故事性和合理性,凑合看吧:
view source
?
01 import java.util.HashMap;
02 import java.util.Map;
03
04 public class Test {
05
06 public static void main(String[] args) {
07
08 // 龙和它的巢穴映射表
09 Map<dragon , Nest> map = new HashMap<dragon , Nest>();
10
11 // 在Map中放入四只克莱恩大陆上的龙
12 map.put(new Dragon("锐刃", 98), new Nest(98));
13 map.put(new Dragon("明镜", 95), new Nest(95));
14 map.put(new Dragon("碧雷", 176), new Nest(176));
15 map.put(new Dragon("玛烈", 255), new Nest(255));
16
17 // 查看宝藏
18 System.out.println("碧雷巢穴中有多少宝藏:" + map.get(new Dragon("碧雷", 176)).getTreasure());
19 }
20
21 }
22
23 // 龙
24 class Dragon {
25
26 Dragon(String name, int level) {
27 this.level = level;
28 this.name = name;
29 }
30
31 // 龙的名字
32 private String name;
33
34 // 龙的级别
35 private int level;
36
37 public int getLevel() {
38 return level;
39 }
40
41 public void setLevel(int level) {
42 this.level = level;
43 }
44
45 public String getName() {
46 return name;
47 }
48
49 public void setName(String name) {
50 this.name = name;
51 }
52
53 }
54
55 // 巢穴
56 class Nest {
57
58 //我研究的龙之常数
59 final int DRAGON_M = 4162;
60
61 // 宝藏
62 private int treasure;
63
64 // 居住的龙的级别
65 private int level;
66
67 Nest(int level) {
68 this.level = level;
69 this.treasure = level * level * DRAGON_M;
70 }
71
72 int getTreasure() {
73 return treasure;
74 }
75
76 public int getLevel() {
77 return level;
78 }
79
80 public void setLevel(int level) {
81 this.level = level;
82 this.treasure = level * level * DRAGON_M;
83 }
84
85 }
编译并运行查看结果:
view source
?
1 Exception in thread "main" java.lang.NullPointerException
2 at Test.main(Test.java:18)
我们发现竟然报了错误,第18行出了空指针错误,也就是说get方法竟然没有拿到预期的巢穴对象。
在这里我们就要研究一下为什么取不到了。我们这里先解释一下HashMap的工作方式。
假设现在有个6张中奖彩票的存根,放在5个桶里(彩票首位只有1-5,首位是1的就放在一号桶,是2的就放在2号桶,依次类推),现在你拿了3张彩 票来兑奖,一个号码是113,一个号码是213,一个号码是313。那么现在先兑第一张,取出一号桶里的存根发现存根号码和你的号码不符,所以你第一张没 中奖。继续兑第二张,二号桶里就没存根所以就直接放弃了,把三号桶里的所有彩票存根都拿出来对应一番,最后发现有一个存根恰好是313,那么恭喜你中奖 了。
HashMap在确定一个键对象和另一个键对象是否是相同时用了同样的方法,每个桶就是一个键对象的散列码值,桶里放的就是散列码相同的彩票存根, 如果散列码不同,那么肯定没有相关元素存在,如果散列码相同,那么还要用键的equals()方法去比较是否相同,如果相同才认为是相同的键。简单的说就 是 hashCode()相同 && equals()==true 时才算两者相同。
到了这里我们应该明白了,在没有重写一个对象的hashcode()和equals()方法之前,它们执行的是Object中对应的方法。而 Object的hashcode()是用对象在内存中存放的位置计算出来的,每个对象实例都不相同。Object的equals()的实现更简单就是看两 个对象是否==,也就是两个对象除非是同一个对象,否则根本不会相同。因此上面的例子虽然都是名字叫碧雷的龙,但是HashMap中却无法认可它们是相同 的。
因此我们只有重写Key对象的hashCode()和equals()方法,才能避免这种情形出现,好在Eclipse可以帮我们自动生成一个类的hashCode()和equals(),我们把上面的例子加上这两个方法再试试看:
view source
?
001 import java.util.HashMap;
002 import java.util.Map;
003
004 public class Test {
005
006 public static void main(String[] args) {
007
008 // 龙和它的巢穴映射表
009 Map<dragon , Nest> map = new HashMap<dragon , Nest>();
010
011 // 在Map中放入四只克莱恩大陆上的龙
012 map.put(new Dragon("锐刃", 98), new Nest(98));
013 map.put(new Dragon("明镜", 95), new Nest(95));
014 map.put(new Dragon("碧雷", 176), new Nest(176));
015 map.put(new Dragon("玛烈", 255), new Nest(255));
016
017 // 查看宝藏
018 System.out.println("碧雷巢穴中有多少宝藏:" + map.get(new Dragon("碧雷", 176)).getTreasure());
019 }
020
021 }
022
023 // 龙
024 class Dragon {
025
026 Dragon(String name, int level) {
027 this.level = level;
028 this.name = name;
029 }
030
031 // 龙的名字
032 private String name;
033
034 // 龙的级别
035 private int level;
036
037 public int getLevel() {
038 return level;
039 }
040
041 public void setLevel(int level) {
042 this.level = level;
043 }
044
045 public String getName() {
046 return name;
047 }
048
049 public void setName(String name) {
050 this.name = name;
051 }
052
053 @Override
054 public int hashCode() {
055 final int PRIME = 31;
056 int result = 1;
057 result = PRIME * result + level;
058 result = PRIME * result + ((name == null) ? 0 : name.hashCode());
059 return result;
060 }
061
062 @Override
063 public boolean equals(Object obj) {
064 if (this == obj)
065 return true;
066 if (obj == null)
067 return false;
068 if (getClass() != obj.getClass())
069 return false;
070 final Dragon other = (Dragon) obj;
071 if (level != other.level)
072 return false;
073 if (name == null) {
074 if (other.name != null)
075 return false;
076 } else if (!name.equals(other.name))
077 return false;
078 return true;
079 }
080
081 }
082
083 // 巢穴
084 class Nest {
085
086 //我研究的龙之常数
087 final int DRAGON_M = 4162;
088
089 // 宝藏
090 private int treasure;
091
092 // 居住的龙的级别
093 private int level;
094
095 Nest(int level) {
096 this.level = level;
097 this.treasure = level * level * DRAGON_M;
098 }
099
100 int getTreasure() {
101 return treasure;
102 }
103
104 public int getLevel() {
105 return level;
106 }
107
108 public void setLevel(int level) {
109 this.level = level;
110 this.treasure = level * level * DRAGON_M;
111 }
112
113 }
编译并运行查看结果:
view source
?
1 碧雷巢穴中有多少宝藏:128922112
这一次正常输出了,真不容易^_^
好了本讲就到这里。
发表评论
-
<E>、<T>又是什么其它的含义呢?
2011-12-22 09:12 987E Element T or S Type K Key, as ... -
Java线程唤醒与阻塞
2011-11-24 16:27 2835阻塞指的是暂停一个线 ... -
Reader 与 inputStream
2011-11-11 15:41 982统计a.txt文件的字节数和字符数 import java ... -
JAVA中mark()和reset()用法
2011-11-11 14:47 3614根据JAVA官方文档的描述 ... -
java解惑系列笔记
2011-10-31 11:05 1141本文内容摘自臧圩人的<<java面试解惑>& ...
相关推荐
Java集合分类总结 Java集合分类总结是Java语言中的一种容器,用于存储和管理多个对象。集合可以自动扩容,部分集合允许存放不同类型的元素。集合的主要分类有List、Set、Map等。 List集合是一种有序列表,允许存放...
本文将对Java集合框架中的Collection接口及其相关接口、类进行深入的探讨。 首先,Collection接口是所有单值容器的基础,它是Set、List和Queue接口的父接口。Collection接口定义了通用的操作方法,如`add()`用于...
### Java集合类总结 在Java开发中,集合类(Containers)是极其重要的组成部分,它们作为开发者日常编程不可或缺的工具,不仅让代码变得更加简洁、高效,还能显著提升程序的功能性和灵活性。本文将对Java标准类库中...
JAVA集合类总结[整理].pdf
"Java集合类总结" Java集合类是Java语言中的一种重要数据结构,用于存储和管理数据。Java集合类可以分为两种:Collection接口和Map接口。Collection接口有两个子接口:List接口和Set接口。List接口是有序的,可以...
### Java集合类详解总结 在Java编程中,集合框架(Collection Framework)是处理一组对象的强大工具,它提供了标准的数据结构来存储和操作这些对象。Java集合框架主要包括`Collection`、`Set`、`List`、`Queue`、`...
### Java集合框架总结 #### 一、Java集合框架概述 Java集合框架是Java标准库的一部分,它提供了一系列的接口和类来存储和操作各种类型的对象集合。这些接口和类遵循一致的设计模式,使得开发人员可以方便地管理和...
Java 集合类面试题总结 Java 集合类是 Java 语言中的一种重要组件,用于存储和操作数据。下面总结了 Java 集合类的一些常见问题和答案。 HashMap 和 Hashtable 的区别 HashMap 和 Hashtable 都是 Java 中的散列表...
### Java集合排序及Java集合类详解 #### 一、集合框架概述 集合框架是Java编程语言的核心组件之一,用于组织和操作数据集。Java集合框架提供了多种数据结构,包括列表(List)、集(Set)和映射(Map),这些数据结构...
总结来说,Java集合类通过提供丰富的接口和实现,使得Java开发者可以灵活选择适合特定需求的数据结构,提高代码的可读性和性能。理解并熟练掌握这些集合类和接口,对于编写高质量的Java程序至关重要。
Java集合类是Java编程语言中不可或缺的一部分,它们提供了一种高效、灵活的方式来存储和操作对象。集合类的主要接口包括Collection、List、Set和Map,这些接口定义了各种操作集合对象的方法,比如添加、删除、修改和...
Java集合类总结 Java集合详解1:一文读懂ArrayList,Vector与Stack使用方法和实现原理 Java集合详解2:Queue和LinkedList Java集合详解3:Iterator,fail-fast机制与比较器 Java集合详解4:HashMap和HashTable Java...
本文将深入讲解Java集合类,特别是Collection接口和其下的List、Set,以及Map接口中的几个重要实现类。 首先,我们来看Collection接口。Collection是最基本的集合接口,它代表一组Object,即它的元素。Collection...
java集合类知识总结--思维导图文件xmind xmind文件类型 总结了java常用集合相关问题 包括map、set、list、数组等
以下是对标题和描述中提到的Java集合类的详细总结: 首先,所有Java集合类都继承自`java.util.Collection`接口。`Collection`接口是所有集合框架的基础,它定义了集合的基本操作,如添加、删除和遍历元素。`...
Java集合类总结 Java集合详解:一文读懂ArrayList,Vector与Stack使用方法和实现原理 Java集合详解:Queue和LinkedList Java集合详解:迭代器,快速失败机制与比较器 Java集合详解:HashMap和HashTable Java集合详解...