码迷,mamicode.com
首页 > 编程语言 > 详细

java集合框架

时间:2020-06-20 17:05:25      阅读:60      评论:0      收藏:0      [点我收藏+]

标签:树结构   bsp   可变   collect   rri   copy   linked   好的   lis   

 

Java集合类简介

java集合大致可以分为List、Set、Map、Queue四种体系,其中Set代表无序、不可重复的集合;List代表有序的、可重复的集合;Map代表具有映射关系的集合;Queue是一种队列集合。

Java集合和数组的区别

1.数组初始化的时候就指定了数组的长度,意味着只能保存定长的数据。而集合可以保存不定长的数据,而且集合还可以保存具有映射关系的数据。

2.数组元素即可以是基本类型的值,也可以是对象。集合里只能存对象,就算是基本类型,也会转成对应的包装类。

java集合类之间的继承关系

java的集合类主要由两个接口派生而出:Collection和Map。

技术图片

 

技术图片

 

 注:Map的结构图有一处错误,dentityHashMapHashMap应该是dentityHashMap。

Collection接口

Collection接口是Set、Queue、List的父接口。Collection接口中定义了多种方法可供其子类进行实现,以实现数据操作,如下:

技术图片

 

使用Iterator遍历集合元素

 Iterator接口经常被称作迭代器,主要用于遍历集合中的元素。

技术图片

Iterator的运用实例:

public static void main(String[] args) {
    List<Dog> arrayList = Arrays.asList(new Dog(1,1),new Dog(2,2));
    Iterator<Dog> iterator = arrayList.iterator();
    while(iterator.hasNext()){
        Dog string = iterator.next();
        string.setAge(3);
        System.out.println(string);
    }
    System.out.println(arrayList.toString());
}

 

输出:

Dog{age=3, age2=1}
Dog{age=3, age2=2}
[Dog{age=3, age2=1}, Dog{age=3, age2=2}]

 

这里可以注意到当我们修改iterator返回对象的属性时,集合中对象的属性也会随着改变,所以iterator遍历出来的对象,不是值传递,而是引用传递。但是如果集合中的对象是String的话则不会改变,这是因为String类是不可变的,所以会将引用指向另外的地址。

集合Set

HashSet按Hash算法来存储集合中的元素,因此具有很好的存取和查找性能。

HashSet的特点

1.不能保证元素的排列顺序,顺序可能与添加顺序不同,顺序也有可能发生变化。

2.HashSet不是同步的,如果多个线程访问一个HashSet,则必须通过代码来保证其同步。

3.集合元素值可以是null。

equals()和hashcode()

equals()用来判断两个对象是否一个对象,比较的是两个对象的地址是否相等,而hashcode()是用来取哈希值的,哈希值是一个与地址有关但不相同的值,两个不同的对象有可能哈希值相同。

equals()和==

==

基本类型:比较的是值是否相同

引用类型:比较的是地址是否相同

equals

基本类型:基本类型根本就没有equals方法

引用类型:比较的是地址是否相同

equals方法默认是比较地址是否相同,但是你可以重写该方法,让对象之间进行值的比较。比如String类的equals方法就是被工程师们重写过的,对比的是String对象的值是否相同。所以一般在写代码的时候都建议用equals方法。

hashSet中判断元素是否相等

HashMap集合判断两个元素相等的标准:两个对象的equals方法相等,并且hashCode方法返回值也相等。

HashSet内部是一个HashMap,HashSet存对象会将该对象作为HashMap的key,然后拿一个默认对象作为value。所以HashSet判断是否存在该元素的原理和HashMap判断是否存在该key的原理是一样的。

hashSet存放数据

假如Hashset中有10个内存位置(并不一定是连续的),我要讲Object1存进去,我会得到hashcode值经过算法的转换,算出存放的位置,比如位置3。那么我就去看位置3,如果该位置为空,那我就在该位置新建一个LinkList,将Object1存到表头;如果该位置3有LinkList了,那我就一个个遍历过去,调用equals比较地址,都不相同的情况下,在表尾插入。

LinkedHashSet类

LinkedHashSet是HashSet对的子类,也是根据元素的hashCode值来决定元素的存储位置,同时使用链表维护元素的次序,使得元素是以插入的顺序来保存的。当遍历LinkHashSet集合中的元素时,LinkHashSet将会按元素添加顺序来访问集合中的元素。但是由于要维护元素的插入顺序,在性能上略低于HashSet,但在访问迭代set里的全部元素时有很好的性能。

TreeSet类

TreeSet是SortedSet接口的实现类,TreeSet可以确保元素处于排序状态。

技术图片

TreeSet的排序方法

自然排序:

存放在TreeSet里面的对象需要实现Comparable接口,TreeSet会调用集合中元素的compareTo(Object o)方法来比较元素之间的大小关系,然后将集合元素按升序排序。

TreeSet是根据红黑树结构找到集合元素的存储位置的。

定制排序

TreeSet的定制排序是通过Comparator接口的帮助。该接口包含一个int compare(T o1,T o2)方法,该方法用于比较o1,o2的大小;如果要实现定制排序,则需要在创建TreeSet时,调用一个带参构造器,传入Comparator对象。并有该对象负责集合元素的排序逻辑,集合元素可以不必实现Comparable接口。

public static void main(String[] args){
        Person p1 = new Person();
        p1.age =20;
        Person p2 =new Person();
        p2.age = 30;
        Comparator<Person> comparator = new Comparator<Person>() {

            @Override
            public int compare(Person o1, Person o2) {
                //年龄越小的排在越后面
                if(o1.age<o2.age){
                    return 1;
                }else if(o1.age>o2.age){
                    return -1;
                }else{
                    return 0;
                }
                
            }
        };
        TreeSet<Person> set = new TreeSet<Person>(comparator);
        set.add(p1);
        set.add(p2);
        System.out.println(set);
    }

如果向TreeSet中添加一个可变对象后,并且后面程序修改了该可变对象的实例变量,这将导致它与其他对象的大小顺序发生了变化,但TreeSet不会再次调整它们。下面程序演示这一现象。

TreeSet<Person> set = new TreeSet<Person>();
        Person p1 = new Person();
        p1.setAge(10);
        Person p2 =new Person();
        p2.setAge(30);
        Person p3 =new Person();
        p3.setAge(40);
        set.add(p1);
        set.add(p2);
        set.add(p3);
        System.out.println("初始年龄排序");
        System.out.println(set);
        //p1的年龄修改成50 最大
        p1.age = 60;
        System.out.println("修改p1年龄后集合排序");
        System.out.println(set);
        p2.age = 40;
        System.out.println("修改p2年龄后集合排序");
        System.out.println(set);
        Person p4 = new Person();
初始年龄排序
[Person[age=10], Person[age=30], Person[age=40]]
修改p1年龄后集合排序
[Person[age=60], Person[age=30], Person[age=40]]
修改p2年龄后集合排序
[Person[age=60], Person[age=40], Person[age=40]]

 

所以不推荐修改放入TreeSet集合中元素的关键实例变量。

EnumSet类

EnumSet是一个专为枚举类设计的集合类,EnumSet中所有元素都必须是指定枚举类型的枚举类值,该枚举类类型在创建EnumSet的时候就隐性指定了

Enum的一些特点:

①EnumSet的集合元素也是有序的,以枚举值在枚举类中的定义顺序来排序的。

②EnumSet不能存Null;

③EnumSet是非线程安全的。

④EnumSet类没有暴露任何构造器来创建该类的实例,程序应该通过它提供的static方法来创建EnumSet对象,常用的static方法比如:

enum Sesson{
    SPRING,SUMMER,FALL,WINTER
}
public class Test
{
    public static void main(String[] args) throws ParseException{
        //创建一个EnumSet集合,集合元素就是所有Sesson中的枚举值
        EnumSet es1=EnumSet.allOf(Sesson.class);
        System.out.println(es1); //[SPRING, SUMMER, FALL, WINTER]
    }
}

 

四种Set的性能对比

EnumSet > HashSet > LinkedHashSet > TreeSet

EnumSet内部以位向量的形式存储,结构紧凑、高效,且只存储枚举类的枚举值,所以高效。HashSet次之,LinkedHashSet因为要维护链表,所以比HashSet更慢。TreeSet因为要排序所以最慢。

具体的应用场景:

当需要一个特定排序的集合时,使用TreeSet集合。

当需要保存枚举类的枚举值时,使用EnumSet集合。

当经常使用添加,查询操作时,使用HashSet。

当经常插入排序或使用删除、插入及遍历操作时,使用LinkedHashSet。

 List集合类

与Set不同,List还提供了一个listIterator()方法,该方法返回一个listIterator对象,可以用来前向遍历List,还可以通过add方法,添加元素

ArrayList和Vector

ArrayList和Vector都是基于数组实现的List类,所以ArrayList和Vector类封装了一个动态的、允许再分配的Obje[]数组,ArrayList和Vector都可以用initalCapacity参数来设置该数组的长度,当向ArrayList或Vector中添加元素超过该数组长度时,它们的initalCapacity长度会自动增加,完成扩容,如果不设置,默认为10。

当往ArrayList里面添加对象时,调用add方法,

public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // 数组的大小增加1
    elementData[size++] = e;
    return true;
}

 

在该方法中,先调用一个ensureCapacityInternal方法,顾名思义,该方法用来确保数组中是否还有足够的容量,如果不够,就执行grow方法。

 private void grow(int minCapacity) {
    //......省略部分内容  主要是为了生成大小合适的newCapacity
   //下面这行就是进行了数组扩容
    elementData = Arrays.copyOf(elementData, newCapacity);
}

ArrayList和Vector有相似之处也有不同之处,他们最大的区别就是Vector是线程安全的,所以Vector也会比ArrayList要慢。

ArrayList遍历的三种方法:

①使用迭代器Iterator遍历;②使用for循环遍历;③使用下标遍历。

因为ArrayList是内部是一个数组,所以第一种方法最慢,第三种方法最快。而LinkList是链表结构,所以和ArrayList相反。

LinkedList

LinkedList的实现机制与ArrayList完全不同。LinkedList内部以链表的形式来保存集中中的元素,因此随机访问集合元素时性能较差,但插入和删除性能比较出色。

LinkedList由于维护了一个表头表尾的Node对象的变量。可以进行后续的添加元素到链表中的操作,以及其他删除,插入等操作。也因此实现了双向队列的功能,既可向表头加入元素,也可以向表尾加入元素。

 

java集合框架

标签:树结构   bsp   可变   collect   rri   copy   linked   好的   lis   

原文地址:https://www.cnblogs.com/isgoto/p/13123489.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!