Java 集合

一、 java集合体系

从基本开始学起
在这里插入图片描述

二、Collection体系

Collection接口
|——Collection:单列集合,用来存储一个一个的对象
|————List:有序,可以有重复(“动态”数组)
|——————ArrayList:动态数组;特点:读快改慢;
|——————LinkedList:链表、队列、堆栈;特点:改快读慢;
|——————Vector:一种老的动态数组比List还先有、线程安全、效率低
|————Set:无序,不可重复的(高中的集合:无序、互异)
|——————HashSet:作为Set接口的主要实现类;线程不安全;可以存储null值;(无序,唯一)
|————————LinkedHashSet:作为HashSet的子类,遍历其内部数据时,可以按照添加的顺序遍历
|——————TreeSet:可以按照添加对象的指定属性进行排序。

(一)接口方法的使用

1、boolean add(E e);
向容器中添加元素
2、boolean addAll(Collection<? extends E> c);
向容器中添加集合
3、ArrayList(Collection c)
带参构造器

 //增
    public static void testAddMethod1(){
        Collection collection = new ArrayList();
        //新增元素
        collection.add("123");
        collection.add("字符串类型");//[123, 字符串类型]
        Collection list = new ArrayList(collection);//根据原有的collection创建一个新的集合
        list.add(new User());
        list.addAll(collection);
        //经过两次添加collection
        System.out.println(list);//[123, 字符串类型, User{name='null', age=0}, 123, 字符串类型]
    }

4、boolean remove(Object o);
移除
5、boolean removeAll(Collection<?> c);
移除容器
6、void clear();
清空容器
7、 boolean retainAll(Collection<?> c);
保留新容器中有的元素,获取当前集合和新集合的交际,并返回给当前集合

  //删
    public static void testRemoveMethod2(){
        Collection collection = new ArrayList();
        collection.add("小明");
        collection.add("老李");
        collection.add("赵五");
        Collection collection1 = new ArrayList();
        collection1.add("老李");
        collection1.add("赵五");
        //删除“子”容器所有
        collection.removeAll(collection1);
        System.out.println(collection);//[小明]
//        collection1.clear();
//        System.out.println(collection1);//[]
        collection.addAll(collection1);//[小明, 老李, 赵五]
        collection.retainAll(collection1);//[老李, 赵五]保留collection1中有的元素
    }

8、boolean contains(Object o);
9、boolean containsAll(Collection<?> c);
10、size()
11、iterator()
遍历的方法
12、equals(Object obj):要想返回true,需要当前集合和形参集合的元素都相同。
13、hashCode():返回当前对象的哈希值
14、toArray():集合到数组的转换。相反的是Arrays中的asList()方法

//查
    public static void testUpdateMethod3(){
        Collection collection = new ArrayList();
        collection.add("小明");
        collection.add("老李");
        collection.add("赵五");
        System.out.println(collection.contains("小明"));//true
        Collection collection1 = new ArrayList();
        collection1.add("老李");
        collection1.add("赵五");
        System.out.println(collection.containsAll(collection1));//true
        System.out.println(collection.size());
        // 获取迭代器
        Iterator<String> it = collection.iterator();
        while(it.hasNext()){
            // 输出集合中的每个元素
            System.out.println(it.next());
        }
    }

(二)各容器特性

1 、Collection接口

Collection 接口
Collection 是最基本的集合接口,一个 Collection 代表一组 Object,即 Collection 的元素, Java不提供直接继承自Collection的类,只提供继承于的子接口(如List和set)。
Collection 接口存储一组不唯一,无序的对象。

2、 List 接口

List接口是一个有序的 Collection,使用此接口能够精确的控制每个元素插入的位置,能够通过索引(元素在List中位置,类似于数组的下标)来访问List中的元素,第一个元素的索引为 0,而且允许有相同的元素。
List 接口存储一组不唯一,有序(插入顺序)的对象。
2.1、ArrayList
①该类也是实现了List的接口,主要实现类
②实现了可变大小的数组,随机访问和遍历元素时,提供更好的性能;
③该类是非同步的,线程不安全的,效率高;
④ArrayList 中数组增长当前长度为原来的1.5倍,插入删除效率低。
2.2、LinkedList
①底层使用双向链表存储
②允许有null(空)元素。
③主要用于创建链表数据结构,该类没有同步方法,如果多个线程同时访问一个List,则必须自己实现访问同步,解决方法就是在创建List时候构造一个同步的List。例如:List list=Collections.synchronizedList(newLinkedList(…));
④对于频繁的插入、删除操作,比ArrayList效率高,但LinkedList 查找效率低。
2.3、Vector
①线程安全,效率低
②该类和ArrayList非常相似,古老实现类
③该类允许设置默认的增长长度,默认扩容方式为原来的2倍。
面试题:
ArrayList、LinkedList、Vector三者的异同?
同:三个类都是实现了List接口,存储数据的特点相同:存储有序的、可重复的数据。
不同:见上

2.4、List接口中常用方法

 public void test1(){
        //ArrayList源码分析
        ArrayList list = new ArrayList();
        list.add(123);
        list.add(456);
        list.add("AA");
        list.add(new User("sgh",12));
        list.add(456);
        System.out.println(list);
        list.add(1,"BB");//[123, BB, 456, AA, User{name='sgh', age=12}, 456]
        System.out.println(list.get(1));//BB
        System.out.println(list.indexOf(456));//2 ;如果不存在返回-1
        System.out.println(list.lastIndexOf(456));//5
        System.out.println(list.remove(1));//BB
        System.out.println(list.set(1, "CC"));//
        System.out.println(list);//[123, CC, AA, User{name='sgh', age=12}, 456]
        System.out.println(list.subList(2, 4));//返回左闭右开的子集合[AA, User{name='sgh', age=12}]
    }

2.3.1、Stack
栈是Vector的一个子类,它实现了一个标准的后进先出的栈。

3、Set接口

Set没有定义自己核心方法, 具有与 Collection 完全一样方法的接口,只是行为上不同,Set 不保存重复的元素。
Set 接口存储一组唯一,无序的对象。
无序性:
不等于随机性。存储的数据在底层数组中并非按照数组索引的顺序添加,而是根据数据的hash值决定。
不可重复性:
保证添加的元素按照equals()判断时,不能反悔true,即:相同元素只能一个。
Set添加元素的过程:以HashSet为例:
我们向HashCode中添加元素a,首先调用元素a所在类的hashCode()方法,计算元素a的哈希值,此哈希值接着通过某种算法计算出在HashSet底层数组中的存放位置(即为:索引位置),判断数组位置上是否已经有元素:
①如果此位置上没有其他元素,值a添加成功。
②如果此位置有其他元素则调用a所在类的equals()方法与此索引上其他元素(链表形式存在的多个元素)进行比较。“七上八下”JDK特点。
要求:①重写hashCode和equals方法;②向Set中添加的数据,其所在类一定要重写hashCode、equals方法。相等的对象必须要具有相等的散列码。
3.1、HashSet
该类实现了Set接口,不允许出现重复元素,不保证集合中元素的顺序,允许包含值为null的元素,但最多只能一个。

3.2、LinkedHashSet
具有可预知迭代顺序的 Set 接口的哈希表和链接列表实现。
LinkedHashSet作为HashSet的子类,在添加数据的同时,每个数据还维护了两个引用,记录此数据前后位置;
优点:对于频繁的遍历操作,LinkedHashSet效率高于HashSet
3.3、TreeSet
该类实现了Set接口,可以实现排序等功能。必须添加相同的类型,如果是自定义类型需事先排序接口(自然排序:比较两个对象是否相同的标准为:compareTo()返回0,不再是equals())后实现定制排序。
定制排序代码:

@Test
    public void test3(){
        Comparator com = new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                return 0;
            }
        };
        Set set = new TreeSet(com);//定制排序规则
        //User需实现排序
        set.add(new User("Tom",12));
        set.add(new User("Jerry",21));
        set.add(new User("Mike",13));
        set.add(new User("Jack",15));
        Iterator iterator = set.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }

二、Map体系

声明:Map是独立的一套体系,与Collection有所不同。
Map接口:双列集合,用来存储一对(key-value)一对的数据(像高中的函数:y=f(x))

(一)接口方法基本使用

 @Test
    public void test3(){
        Map map = new HashMap();
        //增加
        map.put("AA", 123);
        map.put(45, 123);
        map.put("BB", 88);
        // 修改
        map.put("AA", 321);
        System.out.println(map);//{AA=321, BB=88, 45=123}
        Map map1 = new HashMap();
        map1.put("CC", 123);
        map1.put("DD", 234);
        map1.putAll(map);
        System.out.println(map1);//{CC=123, DD=234, AA=321, BB=88, 45=123}
        //remove(Object key),移除
        Object cc = map.remove("CC");
        map.clear();//与map = null 有所不同
        System.out.println(map.size());
    }
 @Test
    public void test4(){
        Map map = new HashMap();
        //增加
        map.put("AA", 123);
        map.put(45, 123);
        map.put("BB", 88);
        System.out.println(map.get("BB"));
        //containsKey(Object key)
        boolean bb = map.containsKey("BB");
        System.out.println(bb);
        //containsValue()
        boolean b = map.containsValue(88);
        System.out.println(b);
        System.out.println(map.isEmpty());//是否为空
    }
 @Test
    public void test5(){
        Map map = new HashMap();
        //增加
        map.put("AA", 123);
        map.put(45, 123);
        map.put("BB", 88);
        //遍历所有的key集:keySet()
        Set set = map.entrySet();
        Iterator iterator = set.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
        //遍历所有的value
        Collection values = map.values();
        for (Object obj:values){
            System.out.println(obj);
        }
        //遍历所有的key-value
        //entrySet()
        Set set1 = map.entrySet();
        Iterator iterator1 = set1.iterator();
        while (iterator1.hasNext()) {
            Object obj = iterator1.next();
            //集合中的元素都是entry
            Map.Entry entry = (Map.Entry) obj;
            System.out.println(entry.getKey()+""+entry.getValue());
        }
        //方式二用遍历key的方式修改
    }

(二)各容器特性

|——Map:双列数据,存储key-value对的数据–类似于高中的函数:y = f(x)
|————HashMap :作为Map的主要实现类,线程不安全,效率高;存储null的key和value
|——————LinkedHashMap:保证在遍历map元素时,可以按照添加的顺序实现遍历。
原因:在原有的HashMap底层接口基础上,添加了一对指针,指向前一个合后一个元素。
对于频繁的遍历操作,此类执行效率高于HashMap。
|————TreeMap :保证按照添加的key-value对进行排序,实现排序遍历;此时考虑key的自然排序活定制排序。
底层使用的红黑树。
|————HashTable:作为Map古老的实现类,线程安全的,效率低;不能存储null的key和value
|——————Properties:常用来处理配置文件。key和value都是String类型

HashMap底层:数组+链表(jdk7及之前),之后是数组+链表+红黑树;

面试题:
1、HashMap的底层实现原理?
2、HashMap和Hashtable的异同?
3、CurrentHashMap与Hashtable的异同?

1、Map结构的理解:

Map中的key:无序的、不可重复的,使用Set存储所有的key----->key所在的类重写equals()和hashCode()
Map中value:无序的、可重复的,使用Collection存储所有的value---->value所在类要重写equals()
一个键值对:key-value构成了一个Entry对象。
Map中的entry:无序的、不可重复的,使用Set存储所有的entry

2、HashMap的底层实现原理

以1.7为例
HashMap map = new HashMap()
在实例化以后,底层创建了长度是16的以为数组Entry[ ] table
…可能执行多次put…
map.put(key1,value1);
首先,调用key1所在类的hashCode计算key1哈希值,此哈希值经过某种算法计算以后,得到在Entry数组中的存放位置。
如果此位置上的数组为空,此时的key1-value1添加成功。
如果此位置上的数据不为空,(意味着此位置上存在一个或多个数据(以链表形式存在)),比较key1和已经存在的一个或多个数据的哈希值:如果key1的哈希值与已经存在的数据的哈希值都不相同,此时key1-value1添加成功。
如果key1的哈希值和已经存在的数据的哈希值相同,继续比较:调用key1所在类的equals()方法,比较:如果equals()返回false:此时key1-value1添加成功。如果返回true:使用value1替换value2.
在不断的添加过程中,会涉及到扩容问题,默认的扩容方式:扩容为原来容量的2倍,并将原有的数据复制过来。
jdk8与jdk7在底层实现方式的不同:
①new HashMap():底层没有创建一个长度为16的数组,首次调用put方法是,底层创建长度为16的数组。
②jdk8底层的数组是:Nde(),而非Entry();
③jdk7底层结构只有:数组+链表。jdk8底层结构:数组+链表+红黑树。
当数组的某一个索引位置上的元素以链表形式存在的数据个数>8且当前数组的长度>64时,此时索引位置上所有数据改为使用红黑树存储。

TreeMap简单应用

//向TreeMap中添加key-value,要求key必须是由同一个类创建的对象
    //因为按照key进行排序:自然排序、定制排序
    @Test
    public void test1(){
        TreeMap map = new TreeMap();
        User u1 = new User("Tom",23);
        User u2 = new User("Jerry",23);
        User u3 = new User("SGH",32);
        User u4 = new User("Rose",18);
        map.put(u1,98);
        map.put(u2,98);
        map.put(u3,98);
        map.put(u4,98);

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

    @Test
    public void test2(){
        TreeMap map = new TreeMap(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                if(o1 instanceof User && o2 instanceof User){
                    User user = (User)o1;
                    User user1 = (User)o2;
                    return Integer.compare(user.getAge(),user1.getAge());
                }throw new RuntimeException("输入的类型有误");
            }
        });
        User u1 = new User("Tom",23);
        User u2 = new User("Jerry",23);
        User u3 = new User("SGH",32);
        User u4 = new User("Rose",18);
        map.put(u1,98);
        map.put(u2,77);
        map.put(u3,34);
        map.put(u4,98);

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

Properties

该对象用来处理配置文件。key和value都是String类型。
Demo


    //Properties:常处理配置文件。key和value都是String类型
    public static void main(String[] args) throws Exception{
        Properties properties = new Properties();
        FileInputStream inputStream = new FileInputStream("JDBC.properties");
        properties.load(inputStream);
        String name = properties.getProperty("name");
        String password = properties.getProperty("password");
        System.out.println(name);
        System.out.println(password);
    }

参考:尚硅谷视频、文章:参考文章参考文章

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值