几个java集合类_java中的几个集合类

今天在网上搜索了一下,发现一篇关于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

下面给出一个集合之间的关系图:

92084_thumb1.jpg

上图中加粗线的ArrayList 和 HashMap 是我们重点讲解的对象。下面这张图看起来层级结构更清晰些。

collection_thumb.jpg

我们这里说的集合指的是小写的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做这个例子:

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

}

编译并运行程序,检查结果:

image_thumb3.png

二、几个比较重要的接口和类简介

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版本之前我们使用:

1

List list =new ArrayList();

在Java5版本之后,我们使用带泛型的写法:

1

List list =new ArrayList();

上面的代码定义了一个只允许保存字符串的列表,尖括号括住的类型就是参数类型,也成泛型。带泛型的写法给了我们一个类型安全的集合。关于泛型的知识可以参见这里。

2、ArrayList的使用:

01

List list =new ArrayList();

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之后可以使用自动装箱功能,更方便的导入基本数据类型。

1

List list =new ArrayList();

2

list.add(new Integer(42));

3

list.add(43);

4、ArrayList的排序:

ArrayList本身不具备排序能力,但是我们可以使用Collections类的sort方法使其排序。我们看一个例子:

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 list =new ArrayList();

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()方法:

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接口:

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 list = Arrays.asList("one","two","three","four");

11

12

// 转换成Iterator实例

13

Iterator 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 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的基本使用:

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 map =new HashMap();

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 c = map.values();

32

33

System.out.println("Collection="+c);

34

35

}

36

37

}

编译并运行程序,查看结果:

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这个知识点,所以未必有太强的故事性和合理性,凑合看吧:

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 map =new HashMap();

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

}

编译并运行查看结果:

1

Exception in thread"main" java.lang.NullPointerException

2

at Test.main(Test.java:18)

我们发现竟然报了错误,第18行出了空指针错误,也就是说get方法竟然没有拿到预期的巢穴对象。

在这里我们就要研究一下为什么取不到了。我们这里先解释一下HashMap的工作方式。

image_thumb6.png

假设现在有个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(),我们把上面的例子加上这两个方法再试试看:

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 map =new HashMap();

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

}

编译并运行查看结果:

1

碧雷巢穴中有多少宝藏:128922112

这一次正常输出了,真不容易^_^

好了本讲就到这里。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值