Java集合详解

java中的Collection是一个集合接口。它提供了对集合进行基本操作的通用接口方法。Collection接口在java类库中有很多具体的实现,其意义在于为各种具体的集合提供了最大化的同一操作方式。
Collections是一个包装类,它包含有各种有关集合操作的静态多态方法,就像是一个工具类,服务于java的Collection框架。

Collection是最基本的集合接口,一个Collection代表一组Object。一些Collection允许相同的元素,而有些不行,一些能排序。所有实现Collection接口的类都必须提供两个标准的构造函数:无参数的构造函数用于创建一个空的Collection,有一个Collection参数的构造函数用于创建一个新的Collection,这个新的Collection与传入的Collection有相同的元素,后一个构造函数允许用户复制一个新的Collection。

Collection与数组有两点不同:
1、数组的容量是由限制的,而Collection没有这样的限制,它的容量可以自动调节。
2、Collection只能用于存放对象,数组没有这样的限制,既可以存放对象,也可以存放数据。

Collectin中的一些常用的方法:
add():向集合中添加元素,每add一次就添加一次。
addAll():向集合中添加集合,新集合的长度是两个集合的长度之和。
size():计算集合中元素的个数(即集合的长度)。
isEmpty():判断集合是否为空。
clear():清空集合中的元素,清空后,打印集合显示[]。
contains():判断集合中是否包含指定的元素,如果有就返回true,根据equals方法来判断的。
toArray():把当前集合转变成一个Object型的数组。
containsAll():当前集合如果包含传入集合的所有的元素就返回true。

Collection接口下面派生出来两个子接口 List和Set。

1、List是有序的Collection,使用此接口能够精确的控制每个元素的插入位置。用户能够利用索引(元素在List中的位置)来访问List中的元素,而且List元素有相同的元素。
List接口除了具有Collection接口必备的iterator方法外,List还提供了一个listIterator()方法,和标准的iterator接口相比,ListIterator多了一些add()之类的方法,允许添加、删除、设定元素,还能向前或向后遍历。
实现List接口的常用类有LinkedList、ArrayList、Vector和Stack。

ArrayList类实现了可变大小的数组,它允许所有元素,包括null,线程不同步。此类除了实现了List接口外,还提供了一些方法来操作内部用来存储列表的数组的大小。其底层是可改变大小的数组,特点是:查询快,但是插入、删除、修改都比较慢。当更多的元素添加到ArrayList中时,其大小会动态的增加,内部的元素可以通过get、set方法进行访问。
get(int index):返回此列表中指定位置上的元素。
set(int index,E element):用指定的元素替代此列表中指定位置上的元素。  E:泛型。

LinkedList(不同步)的本质是一个双向链表,特点是:查询较慢,插入、删除对比ArrayList有更好的性能。并且允许所有元素(包括null)。

示例代码:

public class LinkedListDemo01 {

    public static void main(String[] args) {
        LinkedList<String>list = new LinkedList<>();
        list.add("aaa");
        list.addFirst("bbb");
        list.addLast("ccc");
        System.out.println(list);
        
        //逆序遍历  是LinkedList当中独有的方法
        Iterator<String>it = list.descendingIterator();
        while (it.hasNext()) {
            String str = it.next();
            System.out.println(str);
        } 
        
        list.offer("fff");
        System.out.println(list);
        
        System.out.println(list.poll());
        System.out.println(list);
        
        //模仿一下进栈出栈的过程     栈:先进后出,后进先出
        LinkedList<String>list2  = new LinkedList<>();
        list2.push("xxx");
        list2.push("yyy");
        list2.push("zzz");
        
        System.out.println(list2);  //[zzz,yyy,xxx]
        list2.pop();
        System.out.println(list2);//[yyy,xxx]
        list2.pop();  //[xxx]
        list2.pop();
        System.out.println(list2);
    }
}

Vector类非常类似于ArrayList,但是Vector是同步的。由Vector创建的Iterator,虽然和ArrayList创建的是同一个接口,但是因为Vector是同步的,当一个Iterator被创建而且正在被使用,另一个线程改变了Vector的状态,这是调用iterator方法,会抛出ConcurrentModificationException异常。Vector的大小可以根据需求变大或减小。

实例代码:

public class VectorDemo {

    public static void main(String[] args) {
        Vector<String>vector = new Vector<>();
        vector.add("aaa");
        vector.add("ccc");
        vector.addElement("xxx");
        
        System.out.println(vector);
        //vector集合遍历的方法
        Enumeration<String>en = vector.elements();
        
        while (en.hasMoreElements()) {
            String str = en.nextElement();
            System.out.println(str);
        }
    }
}

Set接口:Set是一个不包含重复元素的Collection,更正式的而说:Set不包含满足e1.equals(e2)的元素对e1和e2,所有的重复内容是靠hashCode()和euqals()两个方法区分的,并且最多包含一个null元素。而且Set接口没有提供Collection接口额外的方法。

示例代码:

public class SetDemo01 {

    public static void main(String[] args) {
        Set set = new HashSet<>();
        //添加元素
        set.add("aaa");
        set.add("bbb");
        set.add(new String("aaa"));
        System.out.println(set.size());   //2
        System.out.println(set);
        set.add(1);
        set.add(3);
        set.add(7);
        set.add(5);
        
        System.out.println(set.add(3));  //false
        System.out.println(set.size());
        System.out.println(set);  //[1, 3, aaa, 5, 7, bbb]
        
        System.out.println(set.contains("bbb"));  //true
        
        //思考一个问题:set集合当中会有get方法么 ?   没有
        //遍历set集合
        
        System.out.println("=======增强for循环=======");
        for (Object object : set) {
            System.out.println(object);
        }
        
        System.out.println("======普通for循环=========");
        Object obj[] = set.toArray();
        for (int i = 0; i < obj.length; i++) {
            System.out.println(obj[i]);
        }
        
        System.out.println("=======迭代器=========");
        Iterator it = set.iterator();
        while (it.hasNext()) {
            Object o = it.next();
            System.out.println(o);
        }
    }
}


实现Set接口的两个类分别是HashSet和TreeSet。
1、HashSet:
它是根据hash算法求出的值来存储集合中的元素,所以HashSet具有很好的存取和查找性能。当向HashSet中存放一个元素时,其就会调用hashcode方法来获取此对象的hashcode值,然后根据此值来决定该对象在HashSet中存放的位置,如果该hashcode值对应的地址上已经存放了元素,这时通过equals方法来判断这两个元素,如果返回true,就不存储,否则,就添加成功。HashSet集合中的元素的hashcode值可能相同,所以既要用equals方法来比较一下,相同的hashcode值的对象不一定是同一个对象。
特点:
1、不能保证元素的排列顺序,顺序可能与添加的顺序不同,顺序也可能随时发生变化。
2、HashSet不是同步的,如果多个线程同时访问一个HashSet时,必须要通过代码来保证其同步。
3、Set集合中的元素可以是null,但是只能存放一个。
使用注意:
1.HashSet不保存元素加入的顺序。
2.HashSet集合存放,取出,删除对象都很有效率。
3.对于存放在hashset集合当中的对象对应的类,一定要重写equals(obj)和hashcode()方法,以实现对象的相等判断。
4.Hashset是根据元素的hash码进行存放的,取出时也可以根据hash码快速的找到。

2、TreeSet:
TreeSet集合排序不根据元素插入的顺序,而是根据元素值的大小进行排序,与HashSet通过hashcode值来决定存储顺序是不同的,TreeSet是根据红黑树的数据结构来存取集合元素。
TreeSet集合的排序规则:
1、自然排序:和存入到集合中的元素的类型是相关的。
2、定制排序。

TreeSet集合中存放的元素类型的限制:
存入的元素的数据类型必须是相同的。

自然排序:
TreeSet会调用集合元素的compareTo方法比较元素之间的大小关系,然后将元素中的按照升序进行排列,这种方式就叫做自然排序。
java中提供了Comparable接口,接口中定义了compareTo方法,该方法的返回值是整数类型。实现该接口的类必须实现该方法,通过此方法可以实现此类中大小的比较。当一个对象调用该方法时,与另一个对象想比较obj1.compraeTo(obj2),若返回0,相同,若返回正数,就是1>2,(升序)负数,2>1(降序)。
大部分类在实现compraeTo方法时,必须将比较对象强制转换为相同类型。因为只有相同类的两个实例才有可比性。当一个对象存到TreeSet集合中时也就确定了集合的类型,那么TreeSet会调用此对象的compraeTo方法。

结论:向TreeSet集合中存放的数据必须是同一类的实例,否则就会引起ClassCastException的异常。

向TreeSet集合中添加的对象可以是自定义类的对象,但是自定义类必须实现Comparable接口,还要重写compareTo方法。

定制排序:
可以在TreeSet创建对象时,自定义比较器,
创建TreeSet时使用带参数的构造方法,传入一个比较器的对象。
要实现Comparator<E>  E:对象类型
如:

示例代码:

import java.util.Comparator;
//要求:1.成绩从高到低。
//2.如果成绩相同,年龄从小到大,
//3.如果年龄一致,字典顺序姓名。
//4如果姓名也一致,就同一对象。
public class StudentComparator implements Comparator<Student>{

    @Override
    public int compare(Student o1, Student o2) {
        if (o1.getScore()>o2.getScore()) {
            return -1;
        }else if (o1.getScore()<o2.getScore()) {
            return 1;
        }else {
            if (o1.getAge()>o2.getAge()) {
                return 1;
            }else if (o1.getAge()<o2.getAge()) {
                return -1;
            }else {
                return o1.getName().compareTo(o2.getName());
            }
        }
    }
}

Map:
Map集合是用于保存具有映射关系的数据,其中保存的其实是两组数,一组保存的是Map中的key值,另一组保存的是values值。Map并没有继承Collection接口,而且一个Map中不能包含相同的key,每个key只能映射一个value。
如果把Map中所有的key值放到一起看,那就形成了set

集合(所有key值没有顺序,且不能重复)。
所有的value值放到一起看,就相当于一个list集合,

元素和元素之间是可以重复的,List集合中可以通过整

数的索引拿到对应的值,Map中取出数据通过另外一个

对象作索引,那就是key值,因此,Map集合有时可以被

称之为字典,或者关联数组。
Map当中的常用方法:
 * put: 向map集合当中添加元素,传值key-value;
 * get:返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null。
containsKey:判断map集合当中是否包含指定的Key值。
containsValue:判断map集合当中是否包含一个或者多个指定的value值。
keySet:返回map集合当中的key所组成的set的集合
values:返回map当中所有的value值所组成的Collection
equals:比较map当中的映射关系是否相同
isEmpty:判断该map的内容是否为空
putAll:将指定的map的键值对复制到本map当中。
remove:移除指定的key值对应的key-value对,如果key值存在,返回值为对应的value值。
size:map当中键值对的数量
clear:删除map当中所有的key-value键值对。


TreeMap其实就是一个红黑树的数据结构,TreeMap在存储key-value时会对节点进行排序。
TreeMap会保证所有的key-value都处于有序的状态。
两种排序方式:
1、自然排序:TreeMap中的key值所属的类都实现了comparable接口,且所有的key都是同一个类的对象。
2、定制排序:创建TreeMap时,使用有参的构造,传入一个实现了comparator接口的对象,这个对象负责将TreeMap中的所有的key值排序,如果采用了定制排序,就不要求TreeMap当中的key值所属的类实现compareble接口了。

 

示例代码:

public class Person implements Comparable<Person>{

    private String name;
    private int age;
    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + "]";
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public Person(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    /**
     * 1.年龄升序排序,如果年龄相同就按照姓名排序。
     * */
    @Override
    public int compareTo(Person o) {
        if (this.age>o.age) {
            return 1;
        }else if (this.age<o.age) {
            return -1;
        }else {
            return this.name.compareTo(o.name);
        }
    }
}

TreeMap当中判断两个映射关系是否相同的依据,也是通过重写compareTo方法,如果返回值为0,就认为相同。

[HashSet  HashMap  Hashtable三者之间的区别和联系]
1.HashSet的底层使用了HashMap来实现,但是hashset没有key-value映射关系。
HashMap当中有key-value视图,HashSet当中是不允许出现重复对象的。
2.Hashtable是基于Dictionary这个类的,HashMap是基于AbstractMap,都是Map接口的实现类。
3.Hashtable是同步的,,是线程安全的,而HashMap是不同步的,是线程不安全的。
4.HashMap当中key和value都可以为空值,但是因为HashMap的key值是不允许重复的,
所以key最多只能一个null值。但是value可以有多个空值。
Hashtable就不允许有null,无论是key,还是value。
5.内存初始化大小不同,使用无参数的构造创建对象时,Hashtable初始化长度为11,HashMap初始化长度16.
6.内存扩充时采用的方式也不同,Hashtable :2*old+1   HashMap:2*old
7.hash值计算方式不同,Hashtable是直接使用了对象的hashcode,HashMap则在对象的hashcode基础之上进行了一些加工。

转载于:https://my.oschina.net/u/3423691/blog/877903

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值