zoukankan      html  css  js  c++  java
  • java容器超详细

    前言

    java容器是前人为我们提供的一套用于存储数据和对象的工具。如果你学过C++的STL,可以与之类比。java容器又可以称为Java Collection Framework(JCF)。里面除了存储对象的容器之外,还提供了一套用于处理和操作容器里面的对象的一套工具类。
    整体框架:
    在这里插入图片描述
    下面将介绍List、Set、Map以及工具类Collections和Arrays。

    List

    在这里插入图片描述

    List:列表,是一个接口。它的实现类常用的有LinkedList、ArrayList和Vector。

    LinkedList

    • LinkedList采用双向链表实现的列表,因此可以被用作队列、堆栈、双端队列;顺序访问高效,随机访问性能较差、适用于需要经常添加和删除的数据。
    • LinkedList不支持同步
    package 常用数据结构;
    
    import java.util.Iterator;
    import java.util.LinkedList;
    
    /**
     * @author pony
     * @date 2020/4/28
     */
    public class LinkedListTest {
        public static void main(String[] args) {
            LinkedList<Integer> linked = new LinkedList<>();
            for(int i=0;i<10;++i){
                linked.add(i);
            }
            System.out.println(linked.size());
            linked.addFirst(10);
            linked.add(3,20);
            linked.remove(3);
            LinkedList<Integer> list = new LinkedList<>();
            for(int i=0;i<100000;++i)
                list.add(i);
            traverseByIterator(list);
            traverseByIndex(list);
            traverseByFor(list);
        }
    
        private static void traverseByFor(LinkedList<Integer> list) {
            long start = System.nanoTime();
            for(Integer i:list)
                ;
            long end = System.nanoTime();
            System.out.println("for-each遍历:"+(end-start)+"ms");
        }
    
        private static void traverseByIndex(LinkedList<Integer> list) {
            long start = System.nanoTime();
            for(int i=0;i<list.size();++i)
                list.get(i);
            long end = System.nanoTime();
            System.out.println("随机索引遍历:"+(end-start)+"ms");
        }
    
        private static void traverseByIterator(LinkedList<Integer> list) {
            long start = System.nanoTime();
            Iterator<Integer> iterator = list.iterator();
            while (iterator.hasNext())
                iterator.next();
            long end = System.nanoTime();
            System.out.println("迭代器遍历:"+(end-start)+"ms");
        }
    }
    

    运行结果:
    在这里插入图片描述

    ArrayList

    • ArrayList是采用数组实现的列表,因此它支持随机访问,不适合频繁删除和插入操作。对于需要经常进行查询的数据建议采用此结构。
    • ArrayList与java数组的一个大的区别是ArrayList能够自动扩容
    • ArrayList不支持同步
    package 常用数据结构;
    
    import java.util.ArrayList;
    import java.util.Iterator;
    
    /**
     * @author pony
     * @date 2020/4/28
     */
    public class ArrayListTest {
        public static void main(String[] args) {
            ArrayList<Integer> arrayList = new ArrayList<>();
            for(int i=0;i<5;++i){
                arrayList.add(i);   //这里会自动装箱
            }
            arrayList.add(0); //允许有相同的元素
            arrayList.remove(2);
            arrayList.add(3,9);
            //遍历测试
            ArrayList<Integer> arr1 = new ArrayList<>();
            for(int i=0;i<100000;++i){
                arr1.add(i);
            }
            traverseByIterator(arr1);
            traverseByIndex(arr1);
            traverseByFor(arr1);
        }
    
        private static void traverseByFor(ArrayList<Integer> arr1) {
            long start = System.nanoTime();
            for(Integer i:arr1)
                ;
            long end = System.nanoTime();
            System.out.println("for遍历:"+(end-start)+"ms");
        }
    
        private static void traverseByIndex(ArrayList<Integer> arr1) {
            long start = System.nanoTime();
            for(int i=0;i<arr1.size();++i){
                arr1.get(i);
            }
            long end = System.nanoTime();
            System.out.println("随机索引遍历:"+(end-start)+"ms");
        }
    
        private static void traverseByIterator(ArrayList<Integer> arr1) {
            long start = System.nanoTime();
            Iterator<Integer> iterator = arr1.iterator();
            while (iterator.hasNext())
                iterator.next();
            long end = System.nanoTime();
            System.out.println("迭代器遍历:"+(end-start)+"ms");
        }
    }
    

    运行结果:
    在这里插入图片描述

    Vector

    Vector用法和ArrayList用法很相似,它们的区别在于Vector是线程同步的而且Vector有另外的遍历方式。这里将不再赘述。

    总结

    对于不同的数据我们应该根据其特点采用不同的list,而不是一中list用到底。要学会灵活使用。

    Set

    Set:集合,和数学中的集合类似。
    特点:

    1. 确定性:对任一对象都能判定它是否属于某一个集和
    2. 互异性:一个集和中不会存在两个相同(内容相同)的对象
    3. 无序性:集和里面的元素没有顺序
      在这里插入图片描述
      HashSet、LinkedHashSet、TreeSet里面存放的都要是对象,不能是基本数据类型。

    HashSet

    基于散列函数的集和,采用HashMap实现,可以容纳null元素,不支持同步(可以通过Collections.synchronizedSet(new HashSet<…>()来使它同步)

    package 常用数据结构;
    
    import java.util.HashSet;
    import java.util.Iterator;
    
    /**
     * @author pony
     * @date 2020/4/28
     */
    public class HashSetTest {
        public static void main(String[] args) {
            HashSet<Integer> hs = new HashSet<>();
            for(int i=0;i<5;++i)
                hs.add(i);
            hs.add(1);  //无效的语句,因为集合中已经有1了。
            hs.add(null); //可以容纳null元素
            /**
             * 测试两种遍历
             */
            HashSet<Integer> hs1 = new HashSet<>();
            for(int i=0;i<100000;++i)
                hs1.add(i);
            long start = System.nanoTime();
            Iterator<Integer> iterator = hs1.iterator();
            while (iterator.hasNext())
                iterator.next();
            long end = System.nanoTime();
            System.out.println("迭代器遍历:"+(end-start)+"ms");
            start = System.nanoTime();
            for(Integer item:hs1)
                ;
            end = System.nanoTime();
            System.out.println("for-each遍历:"+(end-start)+"ms");
        }
    }
    

    运行结果:
    在这里插入图片描述

    HashLinkedSet

    继承HashSet ,基于散列函数和双向链表的集和,可以容纳null元素,通过双向链表维护了插入顺序,从而支持排序,但不支持同步(可以通过Collections.synchronizedSet(new HashSet<…>()来使它同步)

    代码和上面类似。把HashSet改成LinkedHashSet即可
    

    运行结果:
    在这里插入图片描述

    TreeSet

    基于树结构的集和,印次支持排序,不能容纳null元素,同样不支持同步

    package 常用数据结构;
    
    import java.util.TreeSet;
    
    /**
     * @author pony
     * @date 2020/4/28
     */
    public class TreeSetTest {
        public static void main(String[] args) {
            TreeSet<Integer> ts = new TreeSet<>();
            for(int i=0;i<10;++i)
                ts.add(i);
            ts.add(100);
            ts.add(20);
            ts.add(45);
            for(Integer item:ts)
                System.out.println(item);
    //        ts.add(null); //错误,不支持添加null元素
            ts.add(1); //重复
        }
    }
    
    

    在这里插入图片描述

    总结

    • 判定是否是重复元素的原则
      • HashSet、LinkedHashSet
      1. 判断两个对象的hashcode()是否相同,如果不同,返回flase
      2. 如果hashcode()相同,则调用equals()方法判断内容是否相同。相同返回true,不同返回flase
    package 常用数据结构;
    
    import java.util.HashSet;
    import java.util.LinkedHashSet;
    
    /**
     * @author pony
     * @date 2020/4/28
     */
    public class HashSetEqualsRuleTest {
        public static void main(String[] args) {
    
            HashSet<Cat> cats = new HashSet<>();
            cats.add(new Cat(1));
            cats.add(new Cat(2));  //这里将看成是两个对象,因为hashcode方法返回的值不一样
            cats.add(new Cat(2));
            System.out.println(cats.size());  //3
            //重写了hashcode()和equals()
            HashSet<Dog> dogs = new HashSet<>();
            dogs.add(new Dog(1));
            dogs.add(new Dog(2)); //这里是一个对象,因为重写了它的hashcode方法使得返回值一样
            dogs.add(new Dog(2));
            System.out.println(dogs.size());  //2
    
            LinkedHashSet<Cat> cats1 = new LinkedHashSet<>();
            cats1.add(new Cat(1));
            cats1.add(new Cat(2));
            cats1.add(new Cat(2));
            System.out.println(cats1.size());  //3
            //重写了hashcode()和equals()
            LinkedHashSet<Dog> dogs1 = new LinkedHashSet<>();
            dogs1.add(new Dog(1));
            dogs1.add(new Dog(2));
            dogs1.add(new Dog(2));
            System.out.println(dogs1.size());  //2
    
        }
    }
    class Cat{
        public int size;
    
        public Cat(int size) {
            this.size = size;
        }
    }
    class Dog {
        public  int size;
    
        public Dog(int size) {
            this.size = size;
        }
    
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Dog dog = (Dog) o;
            return size == dog.size;
        }
    
        @Override
        public int hashCode() {
            return size;
        }
    
        @Override
        public String toString() {
            return "Dog{" +
                    "size=" + size +
                    '}';
        }
    }
    
    
    • TreeSet
      添加到TreeSet里面的元素都必须实现comparable接口。因为在添加元素时会调用接口里面的compareTo()方法来比较是否是同一个元素。
    package 常用数据结构;
    
    import java.util.TreeSet;
    
    /**
     * @author pony
     * @date 2020/4/28
     */
    public class TreeSetEqualsRuleTet {
        public static void main(String[] args) {
    //        TreeSet<Cat> cats = new TreeSet<>();
    //        cats.add(new Cat(1));  //会报错,因为没有实现Compareable接口
    //        cats.add(new Cat(1));
    //        System.out.println(cats.size());
            TreeSet<Tigger> tiggers = new TreeSet<>();
            tiggers.add(new Tigger(1));
            tiggers.add(new Tigger(2));
            tiggers.add(new Tigger(1));
            System.out.println(tiggers.size());
        }
    }
    class Tigger implements Comparable{
        public int size;
    
        public Tigger(int size) {
            this.size = size;
        }
    
        public int getSize() {
            return size;
        }
    
        @Override
        public int compareTo(Object o) {
            System.out.println("in Tigger compareTo");
            return size-((Tigger)o).getSize();
        }
    }
    

    运行结果:
    在这里插入图片描述

    Map

    Map是一类重要的数据结构。类似于数学中的函数,key对应自变量x、value对应因变量y、散列函数对用f
    在这里插入图片描述

    Hashtable

    key和value都不能为空,HashTable是线程安全的、同步的,但只适合用于小数据量

    package 常用数据结构;
    
    import java.util.Hashtable;
    import java.util.Iterator;
    import java.util.Map;
    
    /**
     * @author pony
     * @date 2020/4/28
     */
    public class HashtableTest {
        public static void main(String[] args) {
            Hashtable<Integer, String> ht = new Hashtable<>();
    //        ht.put(1,null); 报错
    //        ht.put(null,"1"); 报错
    //        ht.put(null,null); 报错
            ht.put(1,"111");
            ht.put(2,"222");
            ht.put(3,"3333");
            ht.contains("111");
            ht.containsValue("111");
            ht.containsKey(0);
            /**
             * 三种遍历方式
             */
            ht.clear();
            for(int i=0;i<100000;++i)
                ht.put(i,"aaaa");
            //第一种:Entry迭代器遍历
            long start = System.nanoTime();
            Iterator<Map.Entry<Integer, String>> iterator = ht.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry<Integer, String> next = iterator.next();
                next.getKey();
                next.getValue();
            }
            long end = System.nanoTime();
            System.out.println("Entry迭代器遍历:"+(end-start));
            //第二种:keySet迭代器遍历
            start=System.nanoTime();
            Iterator<Integer> iterator1 = ht.keySet().iterator();
            while (iterator1.hasNext()){
                Integer key = iterator1.next();
                String value = ht.get(key);
            }
            end = System.nanoTime();
            System.out.println("keySet迭代器遍历:"+(end-start));
        }
    }
    

    运行结果:
    在这里插入图片描述

    HashMap

    HashMap允许有null,不支持同步(支持通过Collections.synchronizedMap(new Map<…,…>() 实现同步),所以线程不安全。但可以存储大量数据

    package 常用数据结构;
    
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Map;
    
    /**
     * @author pony
     * @date 2020/4/28
     */
    public class HashMapTest {
        public static void main(String[] args) {
            HashMap<Integer, String> ht = new HashMap<>();
            ht.put(1,null);
            ht.put(null,"1");
            ht.put(null,null);
            ht.put(1,"111");
            ht.put(2,"222");
            ht.put(3,"3333");
            ht.containsValue("111");
            ht.containsKey(0);
            Iterator<Integer> iterator2 = ht.keySet().iterator();
            while (iterator2.hasNext()){
                Integer key = iterator2.next();
                System.out.println(key+":"+ht.get(key));
            }
            /**
             * 三种遍历方式
             */
            ht.clear();
            for(int i=0;i<100000;++i)
                ht.put(i,"aaaa");
            //第一种:Entry迭代器遍历
            long start = System.nanoTime();
            Iterator<Map.Entry<Integer, String>> iterator = ht.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry<Integer, String> next = iterator.next();
                next.getKey();
                next.getValue();
            }
            long end = System.nanoTime();
            System.out.println("Entry迭代器遍历:"+(end-start));
            //第二种:keySet迭代器遍历
            start=System.nanoTime();
            Iterator<Integer> iterator1 = ht.keySet().iterator();
            while (iterator1.hasNext()){
                Integer key = iterator1.next();
                String value = ht.get(key);
            }
            end = System.nanoTime();
            System.out.println("keySet迭代器遍历:"+(end-start));
        }
    }
    
    

    运行结果:
    在这里插入图片描述

    LinkedHashMap

    基于双向链表用于维持插入顺序的HashMap,继承自HashMap

    TreeMap

    基于红黑树的Map,可以根据key的自然排序或者compareTo方法排序输出

    Properties

    继承自Hashtable。特有的方法有load()、store()等等。

    总结

    Map的种类有很多,根据实际情况选择合适的Map。

    工具类

    Arrays

    Arrays处理的对象是数组,常用的方法包括排序sort、查找binarySearch、拷贝copy等等

    package 常用数据结构;
    
    import java.util.Arrays;
    import java.util.Random;
    import java.util.stream.IntStream;
    
    /**
     * @author pony
     * @date 2020/4/28
     */
    public class ArraysTest {
        public static void main(String[] args) {
            testSort();
            testSearch();
            testFill();
            testCopy();
            testEquality();
        }
    
        private static void testEquality() {
            int[] a = new int[5];
            int[] b = new int[5];
            Arrays.fill(a,1);
            Arrays.fill(b,1);
            System.out.println(Arrays.equals(a,b));
            b[1]=3;
            System.out.println(Arrays.equals(a,b));
        }
    
        private static void testCopy() {
            Random random = new Random();
            IntStream ints = random.ints(20,1,100);
            int[] a = ints.toArray();
            for(int i:a)
                System.out.println(i);
            int[] ints1 = Arrays.copyOf(a, 4);
            for(int i:ints1)
                System.out.println(i);
        }
    
        private static void testFill() {
            int[] a = new int[10];
            Arrays.fill(a,2,8,100);
            for(int i:a)
                System.out.println(i);
        }
    
        private static void testSearch() {
            Random random = new Random();
            int[] ints = random.ints(5,1,100).toArray();
            ints[ints.length-1]=100;
            int i = Arrays.binarySearch(ints, 100);
            System.out.println("100 in "+i);
        }
    
        private static void testSort() {
            Random random = new Random();
            IntStream ints = random.ints(20,1,100);
            int[] a = ints.toArray();
            System.out.println("排序前:");
            for(int i:a)
                System.out.println(i);
            Arrays.sort(a);
            System.out.println("排序后:");
            for(int i:a)
                System.out.println(i);
        }
    }
    
    

    Collections

    Collections可以操作collections接口及其所有子类、常用的用法和Arrays差不多。但它的sort方法要求被排序对象实现了compareable接口或者传入一个compactor对象(主要针对某些类不能去被修改)

    总结

    Arrays和Collections着两个工具类能够帮我们做很多事情,所以要熟练的应用。避免重复造轮子。

    总结

    写到这,容器的基本知识应该都了解的差不多了,但这只能算是对容器入门了。只是学会了如何去使用。建议以后多多去查阅API和源码。了解其内部是如何实现这些结构的。当你能够自己写出来这些容器的实现时,才算真正的掌握了java容器。

  • 相关阅读:
    阿里云前端周刊
    在没有DOM操作的日子里,我是怎么熬过来的(中)
    【php学习】数组操作
    App之百度云推送
    L2-008. 最长对称子串
    整数划分问题之递归法
    分治法之归并排序(递归+分治)
    L2-005. 集合相似度
    分治法之棋盘覆盖问题
    L2-003. 月饼
  • 原文地址:https://www.cnblogs.com/ma-liner/p/14196589.html
Copyright © 2011-2022 走看看