Java基础之集合框架

时间:2021-11-11 19:41:05

一、集合框架概述

集合的概念         面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的一种方式。
数组和集合类有何不同
        数组虽然也可以存储对象,但长度是固定的;集合长度是可变的。数组中可以存储基本数据类型,集合只能存储对象。
集合类的特点
        集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象。
集合框架的构成及分类 Java基础之集合框架
关系概括: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。

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();  )
{
System.out.println(iter.next());
}
2、使用while循环遍历
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 {
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());
}
}
}
        只有类的实例对象要被采用哈希算法进行存储和检索时,这个类才需要按要求覆盖hashcode方法。即使程序可能暂时不会用到当前类的hashcode方法,但是为他提供一个hashcode方法也不会有什么不好,没准以后什么时候有用到这个方法了,所以通常要求hashcode方法和equals方法一并被同时覆盖
提示:
        (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);
}
}
}