讲集合collection之前,我们先分清三个概念:
colection 集合,用来表示任何一种数据结构
Collection 集合接口,指的是 java.util.Collection接口,是 Set、List 和 Queue 接口的超类接口
Collections 集合工具类,指的是 java.util.Collections 类。
我们这里说的集合指的是小写的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做这个例子:
import java.util.ArrayList;
import java.util.Collection;
public class CollectionTest {
public static void main(String[] args) {
String a = "a",b="b",c="c";
Collection list = new ArrayList();
list.add(a);
list.add(b);
list.add(c);
String[] array = list.toArray(new String[1]);
for(String s : array){
System.out.println(s);
}
}
}
二、几个比较重要的接口和类简介
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<String> list = new ArrayList<String>();
上面的代码定义了一个只允许保存字符串的列表,尖括号括住的类型就是参数类型,也成泛型。带泛型的写法给了我们一个类型安全的集合。关于泛型的知识可以参见这里。
2、ArrayList的使用:
List<String> list = new ArrayList<String>();
list.add("nihao!");
list.add("hi!");
list.add("konikiwa!");
list.add("hola");
list.add("Bonjour");
System.out.println(list.size());
System.out.println(list.contains(21));
System.out.println(list.remove("hi!"));
System.out.println(list.size());
关于List接口中的方法和ArrayList中的方法,大家可以看看JDK中的帮助。
3、基本数据类型的的自动装箱:
我们知道集合中存放的是对象,而不能是基本数据类型,在Java5之后可以使用自动装箱功能,更方便的导入基本数据类型。
List<Integer> list = new ArrayList<Integer>();
list.add(new Integer(42));
list.add(43);
4、ArrayList的排序:
ArrayList本身不具备排序能力,但是我们可以使用Collections类的sort方法使其排序。我们看一个例子:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Test {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("nihao!");
list.add("hi!");
list.add("konikiwa!");
list.add("hola");
list.add("Bonjour");
System.out.println("排序前:"+ list);
Collections.sort(list);
System.out.println("排序后:"+ list);
}
}
编译并运行程序查看结果:
排序前:[nihao!, hi!, konikiwa!, hola, Bonjour]
排序后:[Bonjour, hi!, hola, konikiwa!, nihao!]
5、数组和List之间的转换
从数组转换成list,可以使用Arrays类的asList()方法:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Test {
public static void main(String[] args) {
String[] sa = {"one","two","three","four"};
List list = Arrays.asList(sa);
System.out.println("list:"+list);
System.out.println("list.size()="+list.size());
}
}
6、Iterator和for-each
在for-each出现之前,我们想遍历ArrayList中的每个元素我们会使用Iterator接口:
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
public class Test {
public static void main(String[] args) {
// Arrays类为我们提供了一种list的便捷创建方式
List<String> list = Arrays.asList("one", "two", "three", "four");
// 转换成Iterator实例
Iterator<String> it = list.iterator();
//遍历
while (it.hasNext()) {
System.out.println(it.next());
}
}
}
在for-each出现之后,遍历变得简单一些:
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
public class Test {
public static void main(String[] args) {
// Arrays类为我们提供了一种list的便捷创建方式
List<String> list = Arrays.asList("one", "two", "three", "four");
for (String s : list) {
System.out.println(s);
}
}
}
一、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的基本使用:
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class Test {
public static void main(String[] args) {
Map<Integer,String> map = new HashMap<Integer,String>();
map.put(1, "白菜");
map.put(2, "萝卜");
map.put(3, "茄子");
map.put(4, null);
map.put(null, null);
map.put(null, null);
System.out.println("map.size()="+map.size());
System.out.println("map.containsKey(1)="+map.containsKey(2)); System.out.println("map.containsKey(null)="+map.containsKey(null));
System.out.println("map.get(null)="+map.get(null));
System.out.println("map.get(2)="+map.get(2));
map.put(null, "黄瓜");
System.out.println("map.get(null)="+map.get(null));
Set set = map.keySet();
System.out.println("set="+set);
Collection<String> c = map.values();
System.out.println("Collection="+c);
}
}
编译并运行程序,查看结果:
map.size()=5
map.containsKey(1)=true
map.containsKey(null)=true
map.get(null)=null
map.get(2)=萝卜
map.get(null)=黄瓜
set=[null, 1, 2, 3, 4]
Collection=[黄瓜, 白菜, 萝卜, 茄子, null]
2、HashMap 中作为键的对象必须重写Object的hashCode()方法和equals()方法
下面看一个我花了1个小时构思的例子,熟悉龙枪的朋友看起来会比较亲切,设定了龙和龙的巢穴,然后把它们用Map集合对应起来,我们可以根据龙查看它巢穴中的宝藏数量,例子只是为了说明hashCode这个知识点,所以未必有太强的故事性和合理性,凑合看吧:
import java.util.HashMap;
import java.util.Map;
public class Test {
public static void main(String[] args) {
// 龙和它的巢穴映射表
Map<dragon , Nest> map = new HashMap<dragon , Nest>();
// 在Map中放入四只克莱恩大陆上的龙
map.put(new Dragon("锐刃", 98), new Nest(98));
map.put(new Dragon("明镜", 95), new Nest(95));
map.put(new Dragon("碧雷", 176), new Nest(176));
map.put(new Dragon("玛烈", 255), new Nest(255));
// 查看宝藏
System.out.println("碧雷巢穴中有多少宝藏:" + map.get(new Dragon("碧雷", 176)).getTreasure());
}
}
// 龙
class Dragon {
Dragon(String name, int level) {
this.level = level;
this.name = name;
}
// 龙的名字
private String name;
// 龙的级别
private int level;
public int getLevel() {
return level;
}
public void setLevel(int level) {
this.level = level;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
// 巢穴
class Nest {
//我研究的龙之常数
final int DRAGON_M = 4162;
// 宝藏
private int treasure;
// 居住的龙的级别
private int level;
Nest(int level) {
this.level = level;
this.treasure = level * level * DRAGON_M;
}
int getTreasure() {
return treasure;
}
public int getLevel() {
return level;
}
public void setLevel(int level) {
this.level = level;
this.treasure = level * level * DRAGON_M;
}
}
编译并运行查看结果:
Exception in thread "main" java.lang.NullPointerException
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(),我们把上面的例子加上这两个方法再试试看:
import java.util.HashMap;
import java.util.Map;
public class Test {
public static void main(String[] args) {
// 龙和它的巢穴映射表
Map<dragon , Nest> map = new HashMap<dragon , Nest>();
// 在Map中放入四只克莱恩大陆上的龙
map.put(new Dragon("锐刃", 98), new Nest(98));
map.put(new Dragon("明镜", 95), new Nest(95));
map.put(new Dragon("碧雷", 176), new Nest(176));
map.put(new Dragon("玛烈", 255), new Nest(255));
// 查看宝藏
System.out.println("碧雷巢穴中有多少宝藏:" + map.get(new Dragon("碧雷", 176)).getTreasure());
}
}
// 龙
class Dragon {
Dragon(String name, int level) {
this.level = level;
this.name = name;
}
// 龙的名字
private String name;
// 龙的级别
private int level;
public int getLevel() {
return level;
}
public void setLevel(int level) {
this.level = level;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public int hashCode() {
final int PRIME = 31;
int result = 1;
result = PRIME * result + level;
result = PRIME * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final Dragon other = (Dragon) obj;
if (level != other.level)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
// 巢穴
class Nest {
//我研究的龙之常数
final int DRAGON_M = 4162;
// 宝藏
private int treasure;
// 居住的龙的级别
private int level;
Nest(int level) {
this.level = level;
this.treasure = level * level * DRAGON_M;
}
int getTreasure() {
return treasure;
}
public int getLevel() {
return level;
}
public void setLevel(int level) {
this.level = level;
this.treasure = level * level * DRAGON_M;
}
}
编译并运行查看结果:
碧雷巢穴中有多少宝藏:128922112
这一次正常输出了
分享到:
相关推荐
### Java常用类及集合操作详解 #### 一、Java常用类概述 在Java编程语言中,内置了许多实用的类,这些类提供了丰富的功能,能够帮助开发者高效地完成各种任务。本节将详细介绍其中的一些关键类及其用法。 ##### ...
以上是对Java编程中集合类的相关知识点进行了详细的介绍,包括了集合类的概念、分类、常用接口及其实现类、异常处理以及泛型的使用等重要内容。掌握这些知识点对于深入理解和使用Java集合框架至关重要。
实现该接口的集合类包括三个通用实现类哈希集合类、树集合类和链接哈希集合类。 2. 列表接口 列表是一种有序的元素集合。实现该接口的集合类包括数组链表类和链接链表类。 3. 队列接口 队列是一种先进先出的数据...
集合类可以分为三大类:Collection、List 和 Set。 Collection 是集合框架中的根接口,提供了基本的集合操作,如 add、remove、contains 等。Collection 接口没有实现类,因此需要通过其子接口来实现。 Set 是一个...
### Java集合排序及Java集合类详解 #### 一、集合框架概述 集合框架是Java编程语言的核心组件之一,用于组织和操作数据集。Java集合框架提供了多种数据结构,包括列表(List)、集(Set)和映射(Map),这些数据结构...
Java 集合框架概述 Java 集合框架是 Java 语言中提供的一种统一的标准体系结构,...Java 集合框架是 Java 语言中的一种重要组件,提供了丰富的接口和类,简化了集合操作,并提高了编程效率、代码可读性和可维护性。
实验分为三个部分,分别围绕Math类、基本类型的包装类、日期类(Date和Calendar)、以及动态数组Vector类展开。 #### 实验内容与设备 实验在Windows环境下进行,采用Eclipse作为开发工具。实验内容设计了三个练习...
`List`是另一种常用的集合类,它允许重复元素,并且元素具有明确的顺序。 - **特点**: - 有序:每个元素都有自己的索引位置。 - 允许重复:可以向`List`中添加任意数量的相同对象。 - **常见实现类**: - `...
### 细说Java之常用集合类 #### 一、引言 在Java开发过程中,我们经常需要处理数据的集合操作,比如存储、检索、排序等。为了方便开发者使用,Java SDK提供了一系列内置的集合类,它们主要位于`java.util`包中。...
### Java中常用集合类和接口详解 #### 一、引言 在Java编程中,集合类(Collections)是非常重要的组成部分,它们提供了灵活的数据管理和组织方式。本文将详细介绍Java中的主要集合类及其接口,帮助读者更好地理解...
本文将深入探讨Java集合类的汇总,包括List、Set和Map这三大核心接口及其实现类。 首先,让我们从List接口开始。List是一种有序的集合,允许有重复元素,并且支持通过索引来访问元素。ArrayList和LinkedList是List...
- **抽象类**:共有五个抽象类,分别是对六个集合接口的实现进行部分封装,方便开发者根据需要进行扩展,从而实现更灵活的自定义集合类。 - **实现类**:共有八个具体的实现类,包括`ArrayList`、`LinkedList`、`...
Set 接口的实现类有 HashSet、LinkedHashSet 和 TreeSet 等集合类。 * List(列表):代表一个有序的集合,可以对 List 接口代表的有序集合中每个元素的插入位置进行精确地控制,并利用元素的整数索引(代表元素在...
Java常用工具类是Java开发中不可或缺的一部分,它们提供了一系列便捷的方法,帮助开发者高效地处理各种常见任务。在Java中,最著名的工具类库是`java.util`包,它包含了大量实用类,如集合、日期时间、数学计算、...
### Java集合类详解 #### 一、概述 Java集合框架是Java编程语言中处理数据结构的一个重要组成部分。它提供了一套标准的接口和实现来帮助开发者高效地存储、检索和操作对象。Java集合主要包括两大类型:`Collection...
例如`sort()`可以对List进行排序,`reverse()`可以反转List的顺序,`copy()`可以复制一个集合到另一个集合。 三、`java.lang.Math` `Math`类包含了各种数学运算方法,如平方根、绝对值、最大值、最小值等。例如`...
在Java编程中,集合类是一个非常重要的概念,主要用于存储和管理对象的集合。Java集合框架主要包括两大类:`Collection`和`Map`。本篇文章将着重介绍`Collection`部分,并探讨一些在大公司面试中常见的Java集合类...
Java集合框架是Java编程语言中的一个核心部分,它为数据存储和管理...理解并熟练掌握这些集合类的特性和使用方法,对于提升Java编程能力至关重要。通过思维导图的学习,可以有效地梳理知识脉络,让学习过程更为高效。