关于集合的笔记整理

Collections:操作Collection、Map的工具类

 面试题:Collection 和 Collections 的区别?

public class CollectionsTest {
//发现一个不知对错的规律:如果方法是void没有返回值,那么这个方法的举措是在原数组上执行的,而不是新建一个数组执行,因而改变原数组
    /*
    reverse(List):反转List中元素的顺序
    shuffle(List):对List集合元素进行随机排序
    sort(List):根据元素的自然排序对指定List集合元素按升序排序
    sort(List,Comparator):根据指定的Comparator产生的顺序对List集合元素进行排序
    swap(List, int ,int):将指定List集合中的i处元素和j处元素进行交换

    Object max(Collection):根据元素的自然排序,返回给定集合中的最大元素
    Object max(Collection,Comparator):根据Comparator指定的顺序,返回给定集合中的最大元素
    Object min(Collection)
    Object min(Collection,Comparator)
    int frequency(Collection,Object):返回指定集合中指定元素的出现次数
    void copy(List dest,List src):将src中的内容复制到dest中
    boolean replaceAll(List list,Object oldAll,Object newVal):使用新值替换List对象的所有旧值

     */

    @Test
    public void test2(){
        List list = new ArrayList();
        list.add(123);
        list.add(43);
        list.add(765);
        list.add(-97);
        list.add(0);

        //错误写法报异常:IndexOutOfBoundsException: Source does not fit in dest
//        List dest = new ArrayList();先不初始化目的集合的容量,会报下标越界的错误
//        Collections.copy(dest,list);

        List dest = Arrays.asList(new Object[list.size()]);
        System.out.println(dest.size());list.size();
        Collections.copy(dest,list);
        System.out.println(dest);

        /*
        Collections 类中提供了多个 synchronizedXxx()方法,
        该方法可使将指定集合包装成线程同步的集合,从而解决多线程并发访问集合时的线程安全问题

         */
    //返回的list1即为线程安全的List
        List list1 = Collections.synchronizedList(list);
    }

    @Test
    public void test1(){
        List list = new ArrayList();

        list.add(123);
        list.add(43);
        list.add(765);
        list.add(765);
        list.add(-97);
        list.add(0);

        System.out.println(list);

        Collections.reverse(list);
        System.out.println(list);

        Collections.shuffle(list);
        System.out.println(list);

        Collections.sort(list);
        System.out.println(list);

        Collections.swap(list,1,2);
        System.out.println(list);

        int frequency = Collections.frequency(list,765);
        System.out.println(frequency);//2
    }
}

一、集合框架的概述
* 1.集合、数组都是对多个数据进行存储操作的结构,简称Java容器
* 说明:此时的存储,主要指的是内存层面的存储,不涉及到持久化的存储(.txt .jpg .avi 数据库中)
*
*2.1 数组在存储多个数据方面的特点:
*   >一旦初始化以后,其长度就确定了
*   >数组一旦定义好,其元素的类型也就确定了。我们也就只能操作指定类型的数据了
*      比如:String[] arr; int[] arr1; Object[] arr2;
*2.2 数组在存储多个数据方面的缺点:
*    >一旦初始化以后,其长度就不可修改
*    >数组中提供的方法非常有限,对于添加、删除、插入数据等操作,非常不便,同时效率不高
*    >获取数组中实际元素的个数的需求,数组没有现成的属性或方法可用
*    >数组存储数据的特点:有序、可重复。对于无序、不可重复的需求,不能满足
*
* 二、集合框架
* |----Collection接口:单列集合,用来存储一个一个的对象
*    |----List接口:存储有序的、可重复的数据。 --->“动态”数组
*        |----ArrayList、LinkedList、Vector
*
*    |----Set接口:存储无序的、不可重复的数据  --->高中讲的"集合"
*        |----HashSet、LinkedHashSet、TreeSet
*
* |----Map接口:双列集合,用来存储一对(key - value)一对的数据  --->高中函数:y=f(x)
*    |----HashMap、LinkedHashMap、TreeMap、Hashtable、Properties
*
* 三、Collection接口中的方法的使用
public class CollectionTest {

    @Test
    public void test1(){
        Collection coll = new ArrayList();

        //add(Object e):将元素e添加到集合coll中
        coll.add("AA");
        coll.add("BB");
        coll.add(123);//自动装箱
        coll.add(new Date());

        //size():获取添加的元素的个数
        System.out.println(coll.size());//4

        //addAll(Collection coll1):将coll1集合中的元素添加到当前集合中
        Collection coll1 = new ArrayList();
        coll1.add(456);
        coll1.add("cc");
        coll.addAll(coll1);

        System.out.println(coll.size());//6
        System.out.println(coll);//相当于coll.toString()

        //isEmpty():判断当前集合是否为空
        System.out.println(coll.isEmpty());//false

        //clear():清空集合元素
        coll.clear();
        //此操作完成后,isEmpty()为true
    }
}

Collection接口中声明的方法的测试
* 结论:
* 向Collection接口的实现类的对象中添加数据obj时,要求obj所在类要重写equals()
public class CollectionTest1 {

    @Test
    public void test1() {
        Collection coll = new ArrayList();//以ArrayList作为collcetion接口的实现类
        coll.add(123);
        coll.add(456);
        coll.add(new String("Tom"));
        coll.add(false);
        coll.add(new Person("Jerry", 20));

        //contains(Object obj):判断当前集合是否包含obj
        //我们在判断时会调用obj对象所在类的equals()
        boolean contains = coll.contains(123);
        System.out.println(contains);//true
        System.out.println(coll.contains(new String("Tom")));//true
        System.out.println(coll.contains(new Person("Jerry", 20)));//false---->true(重写equals)
        //这里new Person是自定义类调用equals(),如果不重写则返回false

        //containsAll(Collection coll1):判断形参coll1中的所有元素是否都存在于当前集合中
        Collection coll1 = Arrays.asList(123, 456);//也可以用这种方法
        System.out.println(coll.containsAll(coll1));//true
    }

    @Test
    public void test2() {
        Collection coll = new ArrayList();//以ArrayList作为collcetion接口的实现类
        coll.add(123);
        coll.add(456);
        coll.add(new String("Tom"));
        coll.add(new Person("Jerry", 20));
        coll.add(false);
        //remove(Object obj):从当前集合中移除obj元素
        coll.remove(123);//remove()方法是boolean类型返回值,删除成功则返回true
                            //remove(123),首先要判断coll里面有没有123(涉及contains),所以要调用equals(),又是比较内容是否相等
                            //则要重写equals(),但这里的123是Interage包装类,包装类本身是自己重写equals()的,因此不用手动重写
        System.out.println(coll);//true
        coll.remove(new Person("Jerry", 20));
        System.out.println(coll);

        //removeAll(Collection coll1):差集: 从当前集合中移除coll1中所有元素
        Collection coll1 = Arrays.asList(123, 456);
        coll.removeAll(coll1);//直接在coll上做出改动
        System.out.println(coll1);
    }

    @Test
    public void test3() {
        Collection coll = new ArrayList();//以ArrayList作为collcetion接口的实现类
        coll.add(123);
        coll.add(456);
        coll.add(new String("Tom"));
        coll.add(new Person("Jerry", 20));
        coll.add(false);

//        //retainAll(Collection coll1):交集:获取当前集合和coll1集合的交集,并返回给当前集合
//        Collection coll1 = Arrays.asList(123, 456, 789);
//        coll.retainAll(coll1);
//        System.out.println(coll);

        //equals(Object obj):要想返回true,需要当前集合和形参集合的元素都相同
        Collection coll2 = new ArrayList();//以ArrayList作为collcetion接口的实现类
        coll2.add(123);
        coll2.add(456);

//        coll2.add(456);
//        coll2.add(123);
//如果添加的元素一样,顺序不一样,equals会false,因为跟ArrayList的有序性有关

        coll2.add(new String("Tom"));
        coll2.add(new Person("Jerry", 20));
        coll2.add(false);

        System.out.println(coll.equals(coll2));//如果上边的retainAll执行了,coll里的元素就不一样了,所以才要注释掉
    }

    @Test
    public void test4(){
        Collection coll = new ArrayList();//以ArrayList作为collcetion接口的实现类
        coll.add(123);
        coll.add(456);
        coll.add(new String("Tom"));
        coll.add(new Person("Jerry", 20));
        coll.add(false);

        //hashCode():返回当前对象的哈希值
        System.out.println(coll.hashCode());

        //集合--->数组:toArray()
        Object[] arr = coll.toArray();
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }

        //拓展:数组--->集合:调用Arrays类的静态方法asList()
        List list = Arrays.asList(new String[]{"AA", "BB","CC"});
//        List list1 = Arrays.asList("AA", "BB","CC");这样写就可以了

        System.out.println(list);

        List arr1 = Arrays.asList(new int[]{123,456});
        System.out.println(arr1.size());//1  这样写会识别为只有一个元素

        List arr2 = Arrays.asList(new Integer[]{123,456});
        System.out.println(arr2.size());//2

        //iterator():返回Iterator接口的实例,用于遍历集合元素。放在IteratorTest.java中测试
    }
}

 集合元素的遍历,使用迭代器Iterator接口

* 1.内部的方法:hasNext()和 next()
* 2.集合对象每次调用iterator()方法都得到一个全新的迭代器对象,默认游标都在集合的第一个元素之前
* 3.内部定义了一个remove(),可以在遍历的时候,删除集合中的元素。此方法不同于集合直接调用remove()
public class IteratorTest {
    @Test
    public void test1(){
        Collection coll = new ArrayList();//以ArrayList作为collcetion接口的实现类
        coll.add(123);
        coll.add(456);
        coll.add(new String("Tom"));
        coll.add(new Person("Jerry", 20));
        coll.add(false);

        Iterator iterator = coll.iterator();
//        //方式一
//        System.out.println(iterator.next());
//        System.out.println(iterator.next());
//        System.out.println(iterator.next());
//        System.out.println(iterator.next());
//        System.out.println(iterator.next());
//        System.out.println(iterator.next());

        //方式二 不推荐
//        for (int i = 0; i <coll.size() ; i++) {
//            System.out.println(iterator.next());
//        }

        //方式三 推荐
        while(iterator.hasNext()){ //hasNext()判断是否还有下一个元素
            //next():①指针下移②将下移以后集合位置上的元素返回
            System.out.println(iterator.next());
        }

//        //错误方式一:
//        Iterator iterator1 = coll.iterator();
//        while ((iterator1.next())!=null){
//            System.out.println(iterator.next());
//
//        }

//        //错误方式二
//        while (coll.iterator().hasNext()){
//            System.out.println(coll.iterator().next());
//        }
    }

        //测试Iterator中的remove()

//如果还未调用next()或在上一次调用next方法之后已经调用了remove方法,再调用remove会报IllegalStateException

    @Test
    public void test3(){
        Collection coll = new ArrayList();//以ArrayList作为collcetion接口的实现类
        coll.add(123);
        coll.add(456);
        coll.add(new String("Tom"));
        coll.add(new Person("Jerry", 20));
        coll.add(false);
        //删除集合中“Tom”
        Iterator iterator = coll.iterator();
        while (iterator.hasNext()){
            Object obj = iterator.next();
            if("Tom".equals(obj)){
                iterator.remove();
            }
        }
        //重新遍历集合
        iterator=coll.iterator();
            while (iterator.hasNext()){
                System.out.println(iterator.next());
            }
    }
}

* |----Collection接口:单列集合,用来存储一个一个的对象
*      |----List接口:存储有序的、可重复的数据。 --->“动态”数组(不用定义数组大小),替换原有数组
*          |----ArrayList:作为List接口的主要实现类;线程不安全,效率高;底层使用Object[]存储
*          |----LinkedList:对于频繁的插入、删除操作,使用此类操作效率比ArrayList高;底层使用双向链表存储
*          |----Vector:作为List接口的古老实现类;线程安全,效率低;底层使用Object[]存储
*
*面试题:ArrayList、LinkedList、Vector三者的异同?
* 同:三个类都实现了List接口,存储数据的特点相同:存储有序的、可重复的数据
* 不同:见上
* List接口中的常用方法
public class ListTest {
    /*
    void add(int index, Object ele):在indx位置插入ele元素
    boolean addAll(int index, Collection eles):从index位置开始将eles中的所有元素添加进来
    Object get(int index):获取指定index位置的元素
    int indexOf(Object obj):返回obj在集合中首次出现的位置
    int lastIndexOf(Object obj):返回obj在集合中末次出现的位置
    Object remove(int index):移除指定index位置的元素,并返回此元素
    Object set(int index, Object ele):设置指定index位置的元素为ele
    List subList(int fromIndex, int toIndex):返回从fromIndex到toIndex位置的左闭右开子集合

    总结:常用方法
    增 add(Object obj)
    删 remove(int index) / remove(Object obj)
    改 set(int index, Object ele)
    查 get(int index)
    插 add(int index, Object ele)
    长度 size()
    遍历  ①Iterator迭代器方式
         ②增强for循环
         ③普通循环

     */
    @Test
    public void test3(){
        ArrayList list = new ArrayList();
        list.add(123);
        list.add(456);
        list.add("AA");

        //方式一:Iterator迭代器
        Iterator list1 = list.iterator();
        while (list1.hasNext()){
            System.out.println(list1.next());
        }

        //方式二:
        for(Object obj : list){//为什么是Object类型?因为ArrayList的底层就是Object[] elementData
            System.out.println(obj);
        }

        //方式三
        for (int i = 0; i <list.size() ; i++) {
            System.out.println(list.get(i));
        }
    }

    @Test
    public void test2(){
        ArrayList list = new ArrayList();
        list.add(123);
        list.add(456);
        list.add("AA");
        list.add(new Person("Tom",12));
        list.add(456);
//int indexOf(Object obj):返回obj在集合中首次出现的位置
        int index = list.indexOf(456);
        System.out.println(index);//1 不存在则返回-1

// int lastIndexOf(Object obj):返回obj在集合中末次出现的位置
        int index1 = list.lastIndexOf(456);
        System.out.println(index1);//4

// Object remove(int index):移除指定index位置的元素,并返回此元素
        Object obj = list.remove(1);
        System.out.println(obj);//456
        System.out.println(list);//[123, AA, Person{name='Tom', age=12}, 456]

// Object set(int index, Object ele):设置指定index位置的元素为ele
        System.out.println(list);//[123, AA, Person{name='Tom', age=12}, 456]
        list.set(1,"CC");
        System.out.println(list);//[123, CC, Person{name='Tom', age=12}, 456]

// List subList(int fromIndex, int toIndex):返回从fromIndex到toIndex位置的子集合
        List subList = list.subList(2, 4);
        System.out.println(subList);//[Person{name='Tom', age=12}, 456]

        System.out.println(list);
    }

        @Test
    public void test1(){
            ArrayList list = new ArrayList();
            list.add(123);
            list.add(456);
            list.add("AA");
            list.add(new Person("Tom",12));
            list.add(456);

            System.out.println(list);//[123, 456, AA, Person{name='Tom', age=12}, 456]

            //void add(int index, Object ele):在indx位置插入ele元素
            list.add(1,"BB");
            System.out.println(list);//[123, BB, 456, AA, Person{name='Tom', age=12}, 456]

//boolean addAll(int index, Collection eles):从index位置开始将eles中的所有元素添加进来
            List list1 = Arrays.asList(1, 2, 3);//Collection eles
            list.addAll(2,list1);//也可以不写index,则默认将list1加到最后面
            System.out.println(list);//[123, BB, 1, 2, 3, 456, AA, Person{name='Tom', age=12}, 456]


            System.out.println(list.size());//6+3

//            list.add(list1);//把list1里面的元素识别成1个了
//            System.out.println(list.size());//6+1

//            Object get(int index):获取指定index位置的元素
            System.out.println(list.get(1));

        }
}

 

一、Map的实现类的结构
* |---Map:双列数据,用于存储key-value对的数据  ---类似于高中的函数:y=f(x)
*      |---HashMap:作为Map的主要实现类;线程不安全的,效率高;存储null的key和value
* (HashMap的子类)|---LinkedHashMap:保证在遍历map元素时,可以按照添加的顺序实现遍历
*                      原因:在原有的HashMap底层结构基础上,添加了一对指针,指向前一个和后一个元素
*                       对于频繁的遍历操作,此类执行效率高于HashMap
*      |---TreeMap:保证按照添加的key-value对进行排序,实现排序遍历。此时考虑key的自然排序或定制排序
*                   底层使用红黑树
*      |---Hashtable:作为古老的实现类;线程安全,效率低;不能存储null的key和value
*         |---Properties:常用来处理配置文件。key和value都是String类型
*
*
*
*      HashMap的底层:数组+链表(jdk7及之前)
*                    数组+链表+红黑树(jdk8)
*
* 面试题:
* 1.HashMap的底层实现原理?
* 2.HashMap和Hashtable的异同?
* 3。CurrentHashMap和Hashtable的异同?
*
* 二、Map结构的理解
*   Map中的key:无序的、不可重复的,使用Set存储所有的key --->key所在的类要重写equals()和hashCode() (以hashMap为例)
*   Map中的value:无序的、可重复的,使用Collection存储所有的value--->value所在的类要重写equals()
*   一个键值对:key-value构成一个Entry对象
*   Map中的entry:无序的、不可重复的,使用Set存储所有的entry
*
*
* 三、HashMap的底层实现原理?以jdk7为例说明:
*      HashMap map = new HashMap();
*      在实例化以后,底层创建了长度为16的一维数组Entry[] table
*      ...可能已经执行过多次put...
*      map.put(key1,value1):
*      首先,调用key1所在类的hashCode()计算key1哈希值,此哈希值经过某种算法计算后,得到在Entry数组中的存放位置。
*      如果此位置上的数据为空,此时的key1-value1添加成功。 --->情况1
*      如果此位置上的数据不为空,(意味着此位置上存在一个或多个数据(以链表的形式存在)),比较key1和已经存在的一个或多个数据
*      的哈希值:
*              如果key1的哈希值与已经存在的数据的哈希值都不相同,此时key1-value1添加成功。 --->情况2
*              如果key1的哈希值与已经存在的某一个数据(key2-value2)的哈希值相同,继续比较;调用key1所在类的equals(key2)方法
*                      如果equals()返回false:此时key1-value1添加成功。 --->情况3
*                      如果equals()返回true:使用value1替换value2
*
*    补充:关于情况2和情况3:此时key1-value1和原来的数据以链表的方式存储。
*
*    在不断的添加过程中,会涉及到扩容问题,当超出临界值(且要存放的位置非空)时,扩容。
*    默认的扩容方式:扩容为原来容量的2倍,并将原有的数据复制过来
*
*    jdk8 相较于jdk7在底层实现方面的不同:
*    1.new HashMap():底层没有创建一个长度为16的数组
*    2.jdk8底层的数组是:Node[],而非Entry[]
*    3.首次调用put()方法时,底层创建长度为16的数组
*    4.jdk底层结构只有:数组+链表。jdk8中底层结构:数组+链表+红黑树
*      当数组的某一个索引位置上的元素以链表形式存在的数据个数 > 8 且当前数组的长度 > 64时,
*      此时此索引位置上的所有数据改为使用红黑树存储
*
*
*      DEFAULT_INITIAL_CAPACITY:HashMap的默认容量,16
*      DEFAULT_LOAD_FACTOR:HashMap的默认加载因子:0.75
*      threshold:扩容的临界值=容量*填充因子=16*0.75=>12
*      TREEIFY_THRESHOLD:Bucket中链表长度大于该默认值,转化为红黑树:8
*      MIN_TREEIFY_CAPACITY:桶中的Node被树化时最小的hash表容量:64
*
* 四、LinkHashMap的底层实现原理(理解)
*
* 五、Map中定义的方法:
* 添加、删除、修改操作:
* Object put(Object key,Object value):将指定key-value添加到(或修改)当前map对象中
* void putAll(Map m):将m中的所有key-value对存放到当前map中
* Object remove(Object key):移除指定key的key-value对,并返回value
* void clear()清空当前map中的所有数据
* 元素查询的操作:
* Object get(Object key):获取指定key对应的value
* boolean containsKey(Object key):是否包含指定的key
* boolean containsValue(Object value):是否包含指定的value
* int size():返回map中key-value对的个数
* boolean isEmpty():判断当前map是否为空
* boolean equals(Object obj):判断当前map和参数对象obj是否相等
* 元视图操作方法:
* Set keySet():返回所有key构成的Set集合
* Collection values():返回所有value构成的Collection集合
* Set entrySet():返回所有key-value对构成的Set集合
*
*
* 总结:常用方法:
* 添加:put(Object key,Object value)
* 删除:remove(Object key)
* 修改:put(Object key,Object value)
* 查询:get(Object key)
* 长度:size()
* 遍历:keySet()、values()、entrySet()
public class MapTest {
    /*
    元视图操作方法:
 * Set keySet():返回所有key构成的Set集合
 * Collection values():返回所有value构成的Collection集合
 * Set entrySet():返回所有key-value对构成的Set集合
     */
    @Test
    public void test4(){
        HashMap map = new HashMap();
        map.put("AA",123);
        map.put(45,1234);
        map.put("BB",56);

        //遍历所有的key集:keySet()
        Set set = map.keySet();
        Iterator iterator = set.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }

        //遍历所有的value集:values()
        Collection values = map.values();
        Iterator iterator1 = values.iterator();
        //也可以用增强for
        while (iterator1.hasNext()){
            System.out.println(iterator1.next());
        }

        遍历所有的key-value
        //方式一:entrySet()
        Set entrySet = map.entrySet();
        Iterator iterator2 = entrySet.iterator();
        while (iterator2.hasNext()){
            Object obj = iterator2.next();
            //entrySet集合中的元素都是entry
            Map.Entry entry = (Map.Entry)obj;
            System.out.println(entry.getKey() + "--->" + entry.getValue());
        }
        System.out.println();

        //方式二:
        Set keySet = map.keySet();
        Iterator iterator3 = set.iterator();
        while (iterator3.hasNext()){
        Object key = iterator3.next();
        Object value = map.get(key);
            System.out.println(key + "--->" + value);
        }
    }

    /*
    元素查询的操作:
 * Object get(Object key):获取指定key对应的value
 * boolean containsKey(Object key):是否包含指定的key
 * boolean containsValue(Object value):是否包含指定的value
 * int size():返回map中key-value对的个数
 * boolean isEmpty():判断当前map是否为空
 * boolean equals(Object obj):判断当前map和参数对象obj是否相等
     */
    @Test
    public void test3() {
        HashMap map = new HashMap();
        map.put("AA",123);
        map.put(45,123);
        map.put("BB",56);
//    Object get(Object key):获取指定key对应的value
        System.out.println(map.get("AA"));//123

//   boolean containsKey(Object key):是否包含指定的key
        System.out.println(map.containsKey(45));//true

//   boolean containsValue(Object value):是否包含指定的value
        System.out.println(map.containsValue(123));//true

//     int size():返回map中key-value对的个数
        int size = map.size();
        System.out.println(size);//3

//  boolean isEmpty():判断当前map是否为空
        System.out.println(map.isEmpty());//false

//  boolean equals(Object obj):判断当前map和参数对象obj是否相等
        HashMap map1 = new HashMap();
        map1.put("AA",123);
        map1.put(45,123);
        map1.put("BB",56);
        System.out.println(map.equals(map1));//true
    }

    /*
    添加、删除、修改操作:
 * Object put(Object key,Object value):将指定key-value添加到(或修改)当前map对象中
 * void putAll(Map m):将m中的所有key-value对存放到当前map中
 * Object remove(Object key):移除指定key的key-value对,并返回value
     */
    @Test
    public void test2(){
        HashMap map = new HashMap();
        //添加
        map.put("AA",123);
        map.put(45,123);
        map.put("BB",56);
        //修改
        map.put("AA",87);

        System.out.println(map);//{AA=87, BB=56, 45=123}

        HashMap map1 = new HashMap();
        map1.put("CC",123);
        map1.put("DD",123);
        map.putAll(map1);

        System.out.println(map);//{AA=87, BB=56, CC=123, DD=123, 45=123}

   //remove(Object key)
        Object value = map.remove("CC");
        //如果remove的key不存在,返回的value是null
        System.out.println(value);//123
        System.out.println(map);//{AA=87, BB=56, DD=123, 45=123}

        //clear()
        map.clear();//与map=null;操作不同
        System.out.println(map.size());//0
        System.out.println(map);//{}
    }

    @Test
    public void test1(){
        HashMap map = new HashMap();
        map.put(null,123);
        //Hashtable中不能存储null
    }
}

 


* 1.Set接口的框架
* |----Collection接口:单列集合,用来存储一个一个的对象
*  *    |----Set接口:存储无序的、不可重复的数据  --->高中讲的"集合"
*  *        |----HashSet:作为Set接口的主要实现类;线程不安全;可以存储null值
*                 |----LinkedHashSet:HashSet的子类;遍历其内部数据时,可以按照添加的顺序遍历
*                                      对于频繁的遍历操作:LinkedHashSet效率高于HashSet
*           |----TreeSet:可以按照添加的对象的指定属性,进行排序。
*
*1.Set接口中没有额外定义的新方法,使用的都是Collection中声明过的方法
*
*2.要求:向Set中添加的数据,其所在类一定要重写hashCode()和equals()
*  要求:重写的hashCode()和equals()尽可能保持一致性:相等的对象必须具有相等的散列码
*        重写两个方法的小技巧:对象中用作equals()方法比较的Field,都应该用来计算hasCode值

一、Set:存储无序的、不可重复的数据

以HashSet为例说明:
1.无序性:不等于随机性。存储的数据在底层数组中并非按照数组索引的顺序添加。而是根据数据的哈希值决定的

2.不可重复性:保证添加的元素按照equals()判断时,不能返回true。即:相同的元素只能添加一个

二、添加元素的过程:以HashSet为例:
    我们向HashSet中添加元素a,首先调用元素a所在类的hashCode()方法,计算元素a的哈希值,
    此哈希值接着通过某种算法计算出在HashSet底层数组中的存放位置(即为:索引位置),判断
    数组此位置上是否已经有元素:
           如果此位置上没有其他元素,则元素a添加成功。————>情况1
           如果此位置上有其他元素b(或以链表形式存在的多个元素),则比较元素a与元素b的hash值:
                如果hash值不相同,则元素a添加成功  ————>情况2
                如果hash值相同,进而需要调用元素a所在类的equals()方法:
                        equals()返回true,则元素a添加失败
                        equals()返回false,则元素a添加成功————>情况3

    对于添加成功的情况2和情况3而言:元素a与已经存在指定索引位置上数据以链表的方式存储
    jdk 7 :元素a放到数组中,指向原来的元素
    jdk 8 :原来的元素在数组中,指向元素a
    总结:七上八下

    HashSet底层:数组+链表的结构(前提 jdk7)
public class SetTest {
 @Test
    public void test1() {
        Set set = new HashSet();
        set.add(465);
        set.add(123);
        set.add("AA");
        set.add("CC");
        set.add(new User("Tom", 12));
        set.add(129);

        Iterator iterator = set.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
//            AA
//            CC
//            465
//            129
//            123
//            Person{name='Tom', age=12}
        }
    }

    //LinkedHashSet的使用
    //LinkedHashSet作为HashSet的子类,在添加数据的同时,每个数据还维护了两个引用,记录此数据前一个数据和后一个数据
    //优点:对于频繁的遍历操作:LinkedHashSet效率高于HashSet
    @Test
    public void test2() {
        Set set = new LinkedHashSet();
        set.add(465);
        set.add(123);
        set.add("AA");
        set.add("CC");
        set.add(new User("Tom", 12));
        set.add(129);

        Iterator iterator = set.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值