本章目录
为了使程序方便地存储和操纵数目不固定的一组数据,JDK类库中提供了Java集合,所有Java集合类都位于java.util包中。与Java数组不同,Java集合不能存放基本数据类型,而只能存放对象。
Java集合类主要由两个接口派生而出,即Collection和Map接口。Collection和Map是Java集合框架的最上层的父接口,这两个接口又包含其他的子接口和实现类。
Java集合主要包括三种类型: Set(集),List(列表),Map(映射)。
Collection集合体系的继承树
实线表示继承关系,虚线表示实现关系
Map体系的继承树
Java集合的三种数据类型存储示意图
1、Set特点
类似于一个罐子,将一个对象添加到Set集合时,Set集合无法记住添加此元素的顺序
Set集合中的元素是不能重复的,否则系统无法准确识别此元素。
2、List特点
类似于一个数组,它可以记录每个元素添加的顺序,但List长度可变。
3、Map特点
Map集合的存放方式,同样类似于一个罐子,但Map集合中的每项数据都由两个值组成。它们分别为key和value,key不可以重复,但是value可以重复。
方法名
说明
boolean add(Object obj)
向集合中添加一个元素
boolean addAll(Collection c)
将集合c的所有元素添加到指定集合中
void clear()
清除集合中的所有元素,此时集合长度变为0
boolean contains(Object obj)
返回集合中是否包含指定的元素
boolean contains(Collection c)
返回集合中是否包含指定的c集合
Boolean isEmpty()
判断集合是否为空。集合长度为0时返回true,否则返回false
Iterator iterator()
返回一个Iterator对象,用于遍历集合中的元素
boolean remove(Object obj)
删除集合中的指定元素obj,当集合中包含一个或多个元素obj时,仅删除第一个符合条件的元素
int size()
返回集合中元素的个数
Object[] toArray()
将当前集合转换成一个Object[]类型的数组
List集合代表一个元素是有序的、且可以重复的、可以为null的集合。
集合中每个元素都有其对应的顺序索引,List集合允许添加重复元素,可以通过索引来访问指定位置的集合元素。
List 的数据结构就是一个序列,存储内容时直接在内存中开辟一块连续的空间,然后将空间地址与索引对应。
List最常见的实现类是ArrayList和LinkedList。
方法名
说明
void add(int index, Object element)
添加对象element到位置index上
boolean addAll(int index, Collection collection)
在index位置后添加容器collection中所有的元素
Object get(int index)
取出下标为index的位置的元素
int indexOf(Object element)
查找对象element在List中第一次出现的位置
int lastIndexOf(Object element)
查找对象element在List中最后出现的位置
Object remove(int index)
删除index位置上的元素,并返回被删除的这个元素
Object set(int index,Object element)
将index位置上的所示对象替换为element并返回被替换
ArrayList是基于数组实现的List类,ArrayList底层是通过一个长度可变的数组实现的。
ArrayList允许对元素进行快速的随机访问,但是向ArrayList中插入与删除元素的速度较慢。
示例: 演示ArrayList类使用方法
//创建ArrayList对象
ArrayList arrayList=new ArrayList();
arrayList.add("JAVA-DEMO");//向集合中添加字符串对象
arrayList.add(new Hero());//向集合中添加用户自定义对象
System.out.println("arrayList集合的大小="+arrayList.size());
for(int i=0;i<arrayList.size();i++) //遍历集合元素
Object obj=arrayList.get(i); //按照下标获取元素
boolean flag=arrayList.contains("JAVA-DEMO"); //是否包含字符串"JAVA-DEMO"
Object obj=arrayList.remove("JAVA-DEMO");//删除指定元素字符串"JAVA-DEMO"
System.out.println("被删除的元素="+obj);
arrayList.set(0, "ANDROID");//将集合下标为0的元素修改为ANDORID
LinkedList类在实现时,采用链表数据结构,所以向LinkedList中插入和删除元素的速度较快,随机访问速度则相对较慢(随机访问是获取指定下标位置的元素)
LinkedList单独具有addFirst()、addLast()、getFirst()、getLast()、removeFirst()和removeLast()方法。这些方法使LinkedList可以作为堆栈、队列和双向队列来使用。
方法名
说明
void addFirst(Object o)
将指定元素o插入列表起始位置
addLast(Object o)
将指定元素o添加至列表末尾处
Object removeFirst()
移除并返回列表的首元素
Object removeLast()
移除并返回列表的首末元素
示例:演示LinkedList类使用方法
LinkedList linkedList=new LinkedList();
ArrayList ayList=new ArrayList();
ayList.add("JAVA-DEMO");
ayList.add('中');
//将ayList对象添加至linkedList集合中
linkedList.add(ayList);
//添加自定义类型对象
linkedList.add(new Hero());
linkedList.addFirst(99.8);//向集合头部添加一个元素
Object obj=linkedList.removeFirst();//删除头部元素
示例:比较ArrayList与LinkedList删除元素的效率
ArrayList aList=new ArrayList(); //创建ArrayList集合
System.out.println("==========ArrayList==========");
long bTime=System.currentTimeMillis(); //获取当前系统的时间(毫秒数表示)
System.out.println("起始时间:"+bTime);
for(int i=0;i<100000;i++)
aList.add("DEMO"+i);//向集合中添加数据
int size=aList.size();
for(int i=0;i<size;i++)
aList.remove(0);//每次都删除集合中的第一个元素
long eTime=System.currentTimeMillis();
System.out.println("结束时间:"+eTime);
System.out.println("ArrayList添加、删除所用时间="+(eTime-bTime)+"毫秒");
//创建LinkedList集合
LinkedList lList=new LinkedList();
...
System.out.println("LinkedList添加、删除所用时间="+(edTime-bginTime)+"毫秒");
示例:比较ArrayList与LinkedList访问元素的效率
ArrayList aList=new ArrayList(); //创建ArrayList集合
System.out.println("==========ArrayList==========");
for(int i=0;i<100000;i++)
aList.add("DEMO"+i);//向集合中添加数据
//获取当前系统的时间(毫秒数表示)
long bTime=System.currentTimeMillis();
System.out.println("开始时间:"+bTime);
for(int i=0;i<1000000000;i++)
aList.get(99999); //每次读取列表末尾元素
long eTime=System.currentTimeMillis();
System.out.println("结束时间:"+eTime);
System.out.println("ArrayList随机访问所用时间="+(eTime-bTime)+"毫秒");
LinkedList lList=new LinkedList(); //创建LinkedList集合
System.out.println("==========LinkedList==========");
...
for(int i=0;i<1000000000;i++)
lList.get(99999); //每次读取列表末尾元素
...
System.out.println("LinkedList随机访问所用时间="+(edTime-bgTime)+"毫秒");
经验:
List就是一个线性表接口,而ArrayList、LinkedList又是线性表的两种典型实现,ArrayList 是基于数组的线性表,而LinkedList是基于链表的线性表。
当对集合元素进行频繁的添加或删除操作时,使用LinkedList效率比较高,因为链表的插入和删除操作效率比较高。
当对集合元素进行频繁的读取操作时,使用ArrayList效率比较高,因为基于数组的线性表的随机访问效率比较高。
Set集合,类似于一个瓶子,“装进”Set集合中的多个对象之间没有明显的顺序。
Set集合不允许包含相同的元素,如果试图将两个相同的元素加入同一个Set集合中,则添加操作失败返回false,且新元素不会被加入其集合中。
HashSet是Set接口的最常用的实现类。HashSet按Hash算法实现存储集合中的元素,因为其具有良好的存储和查找性能。
Set的排列顺序可能与添加顺序不同,Set元素值可以是null。
示例:添加Cat对象到HashSet集合
public class Cat {
private String name;
private String color;
…
public String toString(){ //重新toString()
return "名字:"+this.name+"-"+"毛色:"+this.color;
}
}
public class HashSetTest {
public static void useHashSet(){
HashSet hs=new HashSet();
hs.add("JAVA");
hs.add(new Cat("加菲","黄色"));
hs.add(new Cat("汤姆","青色"));
hs.add(new Cat("加菲","黄色"));
hs.add("JAVA");//添加重复对象"JAVA"
hs.add(100);//添加重复对象"JAVA"
System.out.println("HashSet对象集合="+hs);
}
…..
提问:有两条猫的名字和颜色一摸一样,怎么它们可以一起添加到Set集合?
分析:
这两条猫的名字和颜色一摸一样,但它们equals()返回值为false,hashCode()值也不相等。所以这两条猫不相同。
如果两条猫相同的逻辑是它们名字和颜色相同,则可通过重写Cat类的equals() 和hashCode() 。
示例:重写Cat的equals() 和hashCode()
public boolean equals(Object obj){
if(obj==this){
return true;
}else{
if(obj instanceof Cat){
Cat cat=(Cat)obj;
if(this.name.equals(cat.name) && this.color.equals(cat.color))
return true;
else
return false;
}else
return false;
}
}
//重写hashCode()方法
public int hashCode(){
return this.name.hashCode()*this.color.hashCode();
}
重写hashCode()方法的一般规则如下:
在程序运行时,同一个对象的hashCode()方法应该返回相同的值。
当两个对象通过equals()方法比较返回true时,这两个对象的hashCode()方法应返回相等的值。
象中用作equals()方法比较标准的属性,都应该用于计算hashCode的值。
Iterator接口隐藏了各种Collection实现类的底层细节,该接口提供了遍历Collection集合元素的统一编程接口。
迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构。迭代器通常被称为“轻量级”对象,因为创建它的代价小。
由于Set集合中存储的是无序的元素,因此无法在循环中按照下标获取Set集合中的元素,所以利用Iterator接口遍历Set集合中的元素尤为方便。
方法名
说明
boolean hasNext(Object o)
如果被迭代的集合中的元素没有遍历完成,则返回true
Object next()
返回集合中的下一个元素
Void remove()
将迭代器新返回的元素删除
示例:Iterator迭代器应用案例
HashSet hs=new HashSet();
hs.add(1);
hs.add(new Date());
hs.add("ANDORID");
hs.add(new Cat("加菲","粉色"));
//调用HashSet对象的iterator()方法,返回Iterator实例
Iterator it=hs.iterator();
//使用while循环,循环判断迭代器中是否还有元素
System.out.println("====使用迭代器遍历HashSet集合=====");
while(it.hasNext()){
//获取迭代器中的数据
Object obj=it.next();
System.out.println(obj);
}
Map用于保存具有映射关系的数据。Map集合中保存着两组值,一组值用于保存Map里的key,另外一组值保存Map的value。key和value可以为null。
key和value可以是任意类型的数据。Map的key不允许重复,即同一个Map对象的任何两个key通过equals()方法比较总是返回false。
key和value间存在单向一对一关系,即通过指定的key总能找到唯一的、确定的value。从Map中取出数据时,只要给出指定的key,就可以取出对应的value。
HashMap是Map接口最为常用的实现类,HashMap通过哈希码对其内部的映射关系进行快速查找。
方法名
说明
put(K key,V value)
向映射中添加一对key与value的映射关系
Object get(Object key)
返回映射中key所对应的value。如果该映射中不包含key,则返回null
putAll(Map map)
将映射map所有的键值映射关系添加到当前映射
containsKey(Object key)
如果此映射包含指定键的映射关系,则返回true
containsValue(Object value)
如果此映射将一个或多个键映射到指定的value,则返回true
keySet()
将该集合中的所有键对象以Set集合的形式返回
values()
将该集合中的所有值对象以Collection集合的形式返回
remove(Object key)
如果存在指定的键key,则移除该键的映射关系,并返回与该键对象对应的值对象,否则返回null
clear()
从此映射中移除所有映射关系
isEmpty()
如果此映射未包含键-值映射关系,则返回true
size()
返回此映射中的键-值映射关系的数量
示例:HashMap应用案例
Map hm=new HashMap();
hm.put("JAVA", "DEMO");
hm.put("中国", "北京");
hm.put(1, "one");
hm.put(true,"正确" );
hm.put("中国", "上海");
System.out.println("========HashMap集合添加元素后=======");
System.out.println(hm);
System.out.println("====按照Kye获取对应Value值====");
Object value=hm.get("中国");
System.out.println("key值为中国对应的value值="+value);
System.out.println("HashMap集合的大小="+hm.size());
System.out.println("===遍历HashMap集合===");
//返回存储HashMap集合中的所有的key(键)的Set集合
Set set=hm.keySet();
Iterator it=set.iterator();//返回key集合的Iterator迭代器
while(it.hasNext()){//遍历key
Object key=it.next();//得到HashMap集合中的key值
Object val=hm.get(key);//通过key得到对应的value值
System.out.println("键="+key+"\t"+"值="+val);
}
HashMap与Hashtable的区别
HashMap
Hashtable
允许出现空值、空键
不允许出现空值、空键
线程异步,效率较高
线程同步,效率较低
继承自AbstractMap
继承自Dictionary
手机扫一扫
移动阅读更方便
你可能感兴趣的文章