一、集合框架概述
集合的概念 面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的一种方式。数组和集合类有何不同
数组虽然也可以存储对象,但长度是固定的;集合长度是可变的。数组中可以存储基本数据类型,集合只能存储对象。
集合类的特点
集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象。
集合框架的构成及分类
关系概括:Collection和Map是Java集合框架(Java Collections Framework)的两个主要成员。
List和Set是由Collection接口派生的两个接口,Collection、List、Set、Map都是接口,不能被实例化
下面是Collection和Map两个集合的主要接口及实现类关系以及特点
Collection 接口的接口 是对象的集合
|--List 子接口 元素是有序的,元素可以重复。因为该集合体系有索引
| |--ArrayList 接口实现类 底层的数据结构使用的是数组;线程不安全。特点:查询、修改快,增删慢;
| |--LinkedList 接口实现类 底层使用的是链表数据结构;线程不安全。特点:增删的速度快,查询速度慢
| |--Vector 接口实现类 底层是数组数据结构;线程安全,无论增删改查都慢,被ArrayList替代
|
|--Set 子接口 元素是无序的,并且元素不可以重复
|--HashSet 接口实现类 底层数据结构是哈希表,线程是不安全的
|--TreeSet 接口实现类 底层数据结构是二叉树,可以对集合中的元素进行排序
Map 接口 键值对的集合
|--Hashtable:接口实现类:底层是哈希表数据结构,不可以存入null键null值,线程安全;效率低
|--HashMap: 接口实现类:底层是哈希表数据结构,允许存入null键null值,线程不安全;效率高
|--TreeMap: 接口实现类:底层是二叉树数据结构,线程不安全,可以用于给map集合中的键进行排序
二、Collection集合
Collection 层次结构 中的根接口。Collection 表示一组对象,这些对象也称为 collection 的元素。一些 collection 允许有重复的元素,而另一些则不允许。一些 collection 是有序的,而另一些则是无序的。JDK 不提供此接口的任何直接 实现:它提供更具体的子接口(如 Set 和 List)实现。此接口通常用来传递 collection,并在需要最大普遍性的地方操作这些 collection。
add(e);向集合中添加元素
addAll(collection);将指定 collection 中的所有元素都添加到此 collection 中
删除
remove(e);从此 collection 中移除指定元素的单个实例,如果存在的话
removeAll(collection);移除此 collection 中那些也包含在指定 collection 中的所有元素
clear();移除此 collection 中的所有元素
判断
contains(e);如果此 collection 包含指定的元素,则返回true。
isEmpty(); 如果此 collection 不包含元素,则返回 true。
获取
iterator();返回在此 collection 的元素上进行迭代的迭代器。
size();返回此 collection 中的元素数。
获取交集。
retainAll();获取交集。。
集合变数组。
toArray();
迭代器 迭代是取出集合中元素的一种方式。因为Collection中有iterator方法,所以每一个子类集合对象都具备迭代器。
用法: 1、使用for循环遍历
for(Iterator iter = iterator();iter.hasNext(); )2、使用while循环遍历
{
System.out.println(iter.next());
}
Iterator iter = l.iterator();while(iter.hasNext()){System.out.println(iter.next());}
List集合
List集合元素是有序的,元素可以重复。因为该集合体系有索引。 List的特有方法 增add(index,element);在列表的指定位置插入指定元素
addAll(index,Collection);将指定 collection 中的所有元素都插入到列表中的指定位置
删
remove(index);移除列表中指定位置的元素
改
set(index,element);用指定元素替换列表中指定位置的元素
查
get(index);返回列表中指定位置的元素
subList(from,to);返回列表中指定的fromIndex(包括 )和toIndex(不包括)之间的部分视图
listIterator();返回List集合特有的迭代器
注意:在使用listIterator迭代时候,不可以通过集合对象的方法操作集合中的元素。因为会发生ConcurrentModificationException异常
所以,在迭代时,只能用迭代器的方法操作元素,可是Iterator的方法是有限的,只能对元素进行判断、取出、删除操作。如果想要其他的操作如添加,修改等就需要使用其子接口ListIterator。该接口只能通过List集合的listIterator()方法获取。
ArrayList
ArrayList:底层的数据结构使用的是数组结构:特点,查询、修改速度快,增删慢;线程不同步它是List集合中最常用的一个实现类 代码示例:
public class ListDemo {
@SuppressWarnings({ "rawtypes", "unchecked" })
public static void main(String[] args) {
ArrayList al=new ArrayList();
al.add("java01");
al.add("java02");
al.add("java03");
al.add("java04");
ListIterator li=al.listIterator();
while(li.hasNext()){
Object obj=li.next();
if(obj.equals("java02")){
//li.add("java009");//添加元素
li.set("java008");//删除元素
li.remove();//修改元素
}
}
System.out.println(al);
//逆向遍历
while (li.hasPrevious()) {
System.out.println(li.previous());
}
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public static void method(){
ArrayList al=new ArrayList();
al.add("java01");
al.add("java02");
al.add("java03");
al.add("java04");
System.out.println("原集合:"+al);
//在指定位置添加元素
al.add(1,"java09");
//移除指定位置的元素
al.remove(2);
//修改指定位置上的元素
al.set(0, "java001");
//使用for循环遍历List集合
for(int i=0;i<al.size();i++){
System.out.println("al("+i+")="+al.get(0));
}
//使用迭代器遍历List集合
for(Iterator it=al.iterator();it.hasNext();){
System.out.println("next:"+it.next());
}
System.out.println(al);
System.out.println("index="+al.indexOf("java03"));
//截取List
List sub=al.subList(0, 2);
System.out.println(sub);
}
}
LinkedList
LinkedList:底层使用的是链表数据结构;特点:增删点速度快,查询速度慢LinkedList:特有方法
addFirst()
addLast()
getFirst()
getLast()
获取元素,但不删除元素,如果集合中没有元素,会出现NoSuchElementException
removeFirst()
removeLast()
获取元素,并删除元素,如果集合中没有元素,会出现NoSuchElementException
在jdk1.6出现了替代方法
offerFirst()
offerLast()
peekFirst()
peekLast()
获取元素,但不删除元素,如果集合中没有元素,会返回Null
poolFirst()
poolLast()
获取元素,并删除元素,如果集合中没有元素,会返回Null
Vector
Vector:底层是数组数据结构;线程同步,无论增删改查都慢,被ArrayList替代枚举就是Vector特有的取出方式。
发现枚举和迭代器很像,其实枚举和迭代器是一样的。
因为枚举的名称和方法的名称都过长。
所以被迭代器取代了,枚举也就郁郁而终了
代码示例
public class VectorDemo {
public static void main(String[] args) {
Vector ve = new Vector();
ve.add("java01");
ve.add("java02");
ve.add("java03");
ve.add("java04");
Enumeration en=ve.elements();
while (en.hasMoreElements()) {
System.out.println(en.nextElement());
}
}
}
Set集合
Set集合:元素是无序的(存入和取出的顺序不一定一致),元素不可以重复。Set集合的功能和Collection的功能是一致的
HashSet
HashSet:底层数据结构是哈希表
HashSet是如何保证元素的唯一性呢?
是通过元素的两个方法,hashCode和equals来完成
如果元素hashcode值相同,才会判断equals是否为true
如果元素hashcode值不同,不会调用equals
注意:对于判断元素是否存在以及删除等操作,依赖的方法是元素的hashCode和equals方法,ArrayList 只依赖equals
class Person {只有类的实例对象要被采用哈希算法进行存储和检索时,这个类才需要按要求覆盖hashcode方法。即使程序可能暂时不会用到当前类的hashcode方法,但是为他提供一个hashcode方法也不会有什么不好,没准以后什么时候有用到这个方法了,所以通常要求hashcode方法和equals方法一并被同时覆盖
private String name;
private int age;
Person(String name, int age) {
this.name = name;
this.age = age;
}
public int hashCode() {
return name.hashCode() + age * 27;
}
public boolean equals(Object obj) {
if (!(obj instanceof Person))
return false;
Person p = (Person) obj;
System.out.println(this.name + "..." + p.name);
return this.name.equals(p.name) && this.age == p.age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
public class HashSetTest {
public static void main(String[] args) {
HashSet hs = new HashSet();
hs.add(new Person("zhangsan01", 30));
hs.add(new Person("zhangsan02", 32));
hs.add(new Person("zhangsan03", 33));
hs.add(new Person("zhangsan03", 33));
hs.add(new Person("zhangsan04", 34));
for (Iterator it = hs.iterator(); it.hasNext();) {
Person per = (Person) it.next();
System.out.println(per.getName() + "...." + per.getAge());
}
}
}
提示:
(1)通常来说,一个类的两个实例对象用equals方法比较的结果相等时,他们的哈希码也必需相等,但反之则不成立,即equals方法比较的结果不相等可以有相同的哈希码,或者说哈希码相同的两个对象的equals方法比较结果可以不相等,例如,字符串“BB”和“Aa”的equals方法比较结果肯定不相等,但它们的hashcode方法返回值却相等。
(2)当一个对象被存储进hashSet集合中以后,就不能修改这个对象中的那些参与计算哈希值的字段了,否则,对象修改后的哈希值与最初存储进hashSet集合中的哈希值就不相同了,这中情况下在contains方法使用该对象的当前引用作为参数去hashSet集合中检索对象,也将返回找不到对象的结果,这也会导致无法从hashSet集合中单独删除当前对象,从而造成内存泄漏
TreeSet
TreeSet:可以对集合中的元素进行排序底层数据结构是二叉树,存储的对象必需具备可比性不然会报ClassCastException异常。 保证数据唯一性的依据是compareTo方法返回0
TreeSet排序的第一种方式:让元素自身具备比较性 元素需要实现Comparable接口覆盖compareTo方法这种方式,也称为元素的自然顺序或者默认顺序
TreeSet排序的第二种方式:当元素自身不具备比较性,或者具备的比较性不是锁需要的,这时,就需要集合自身具备比较性,让集合一初始化就有了比较方式
方法:定义一个比较器,将比较器的对象作为参数传递给TreeSet集合的构造函数定义一个类实现Comparator接口,实现compare方法,
两种比较方式都存在时,以比较器为主
代码示例
//实现Comparable接口让元素自身具备比较性
class Teacher implements Comparable{
private String name;
private int age;
public Teacher(String name,int age) {
this.name=name;
this.age=age;
}
public String getName(){
return name;
}
public int getAge(){
return age;
}
@Override
public int compareTo(Object o) {
if(!(o instanceof Teacher))
throw new RuntimeException("不是教师对象");
Teacher t=(Teacher)o;
if(this.age>t.age)
return 1;
if(this.age==t.age){
return this.name.compareTo(t.name);
}
return -1;
}
}
public class TreeSetDemo {
public static void main(String[] args) {
//将比较器的对象作为参数传递给TreeSet集合的构造函数
TreeSet ts=new TreeSet(new MyCompare());
ts.add(new Teacher("lisi01", 22));
ts.add(new Teacher("lisi03", 25));
ts.add(new Teacher("lisi08", 24));
ts.add(new Teacher("lisi06", 26));
ts.add(new Teacher("lisi05", 26));
ts.add(new Teacher("lisi07", 21));
for (Iterator iterator = ts.iterator(); iterator.hasNext();) {
Teacher t=(Teacher)iterator.next();
System.out.println(t.getName()+"..."+t.getAge());
}
}
}
//定义一个比较器
class MyCompare implements Comparator {
@Override
public int compare(Object o1, Object o2) {
Teacher t1 = (Teacher) o1;
Teacher t2 = (Teacher) o2;
int num = t1.getName().compareTo(t2.getName());
if (num == 0) {
return new Integer(t1.getAge()).compareTo(new Integer(t2.getAge()));
}
return num;
}
}
三、Map集合
Map集合:该集合存储键值对,一对一对往里存,而且保证键的唯一性主要方法 1、添加:
V put(K key, V value)
void putAll(Map<? extends K,? extends V> m)
2、删除
void clear()
V remove(Object key)
3、判断
boolean containsKey(Object key)
boolean containsValue(Object value)
boolean isEmpty()
4、获取
V get(Object key)
int size()
Collection<V> values()
Set<Map.Entry<K,V>> entrySet()
Set<K> keySet()
Hashtable
底层是哈希表数据结构,不可以存入null键null值,该集合是线程同步的;jdk1.0,效率低HashMap
底层是哈希表数据结构,允许存入null键null值,该集合是不同步的;jdk1.2,效率高TreeMap
底层是二叉树数据结构,线程不同步,可以用于给map集合中的键进行排序Map的两种取出方式 Set<K> keySet():将map中所有的键存入到set集合。因为set集合具备迭代器
可以用迭代的方式去除所有的键,在根据get方法,获取每一个键对应的值
Set<Map.Entry<K,V>> entrySet() 将映射关系存到Set集合中,再对Set集合进行遍历 示例代码
public class MapDemo2 {
public static void main(String[] args) {
HashMap<String, String> map = new HashMap<String, String>();
map.put("01", "zhangsan1");
map.put("02", "zhangsan2");
map.put("03", "zhangsan3");
map.put("04", "zhangsan4");
// 第一种方式:先获取map集合中所有键的集合
Set<String> keySet = map.keySet();
Iterator<String> it = keySet.iterator();
while (it.hasNext()) {
String key = it.next();
System.out.println(key + "==" + map.get(key));
}
// 第二种方式:将映射关系存到Set集合中,再对Set集合进行遍历
Set<Map.Entry<String, String>> entrySet = map.entrySet();
Iterator<Map.Entry<String, String>> it2 = entrySet.iterator();
while (it2.hasNext()) {
Map.Entry<String, String> entry = (Map.Entry<String, String>) it2.next();
String key = entry.getKey();
String value = entry.getValue();
System.out.println(key + "==" + value);
}
}
}