Java 集合Collection

集合的主要结构:
在这里插入图片描述

1. Collection 接口

单列集合

1.1 Collection 集合的方法

1)添加

    public void testAdd(){
        Collection coll = new ArrayList();
        // 1.添加一个元素
        coll.add("chengyu");
        coll.add(true);
        System.out.println(coll); // [chengyu, true]
        // 2.添加集合(一组元素)
        Collection coll1 = new ArrayList();
        coll1.add("chenglong");
        coll1.add(100);
        coll.addAll(coll1);
        System.out.println(coll); // [chengyu, true, chenglong, 100]
        // 3.添加类对象
        Person per = new Person("chengyu",30);
        coll.add(per);
        System.out.println(coll); // [chengyu, true, chenglong, 100, Person{name='chengyu', age=30}]
    }

2)删除

public void testRemove(){
        Collection coll = new ArrayList();
        coll.add("chengyu");
        coll.add(20);
        System.out.println(coll); // [chengyu, 20]
        // 1.remove
        boolean boo = coll.remove("chengyu"); // 注意:移除类对象要重写equals
        // 是否移除
        System.out.println(boo); // true
        System.out.println(coll); // [20]
        // 2.removeAll
        Collection coll1 = new ArrayList();
        coll1.add("chengyu");
        coll1.add(20);
        coll1.add(40);
        System.out.println(coll1); // [chengyu, 20, 40]

        Collection coll2 = new ArrayList();
        coll2.add("chengyu");
        coll2.add(20);

        coll1.remove(coll2); // 不起作用
        System.out.println(coll1); // [chengyu, 20, 40]
        coll1.removeAll(coll2);
        System.out.println(coll1); // [40]

        // 3.retainAll(移除不同部分,返回交集)
        Collection coll3 = new ArrayList();
        coll3.add("chengyu");
        coll3.add(20);
        coll3.add(40);

        Collection coll4 = new ArrayList();
        coll4.add(20);
        coll4.add(40);

        coll3.retainAll(coll4);
        System.out.println(coll3); // [20, 40]
    }

3)包含

public void testContains(){
        Collection coll = new ArrayList();
        coll.add("chengyu");
        coll.add(20);

        Person per = new Person("chengyu",30);
        coll.add(per);
        // 是否包含单个元素
        System.out.println(coll.contains("chengyu")); // true
        // 是否包含类对象(同一对象)
        System.out.println(coll.contains(per)); // true
        // 是否包含类对象(新建对象)
        System.out.println(coll.contains(new Person("chengyu",30))); // 没有重写Person 中的equals 方法时为false,重写后为true
        // 是否包含形参中所有内容
        Collection coll1 = new ArrayList();
        coll1.add("chengyu");
        coll1.add(20);
        System.out.println(coll.containsAll(coll1)); // true
    }

4)相等

public void testEquals(){
        Collection coll = new ArrayList();
        coll.add("chengyu");
        coll.add(20);

        Collection col2 = new ArrayList();
        col2.add("chengyu");
        col2.add(20);

        // 集合中每个元素是否相等
        System.out.println(coll.equals(col2)); // true
    }

5)转换

public void testTransfor(){
        Collection coll = new ArrayList();
        coll.add("chengyu");
        coll.add(20);
        // 集合转数组
        Object[] objects = coll.toArray();
        for (int i = 0; i < objects.length; i++) {
            System.out.println(objects[i]); // chengyu  // 20
        }
        // 数组转集合
        List<String> list = Arrays.asList(new String[]{"a","b","c"});
        System.out.println(list); // [a, b, c]
        // 注意:基本类型数组转集合时,即使多个元素也会被看作一个元素
        List list1 = Arrays.asList(new int[]{111,222});
        System.out.println(list1); // [[I@32a1bec0]
    }

6)遍历

public void testIterator(){
        // 集合元素的遍历操作(迭代器)
        Collection coll = new ArrayList();
        coll.add("chengyu");
        coll.add(20);

        Iterator iterator = coll.iterator();
        // 迭代
        while (iterator.hasNext()){
            Object obj = iterator.next();
            System.out.println(obj);
            // 移除数据
            if("chengyu".equals(obj)){
                iterator.remove();
            }
        }
        // 重新遍历集合
        Iterator iterator1 = coll.iterator();
        while (iterator1.hasNext()){
            System.out.println(iterator1.next());
        }
        // Java5.0 用于遍历结合和数组,内部还是迭代器
        Collection coll2 = new ArrayList();
        coll2.add("chengyu");
        coll2.add(20);
        for (Object obj : coll2) {
            System.out.println(coll2);
        }
    }

7)其他

public void testOthers(){
        Collection coll = new ArrayList();
        coll.add("chengyu");
        coll.add(20);
        // 1.元素个数
        System.out.println(coll.size());
        // 2.是否为空
        System.out.println(coll.isEmpty());
        // 3.清空
        coll.clear();
        System.out.println(coll.isEmpty());
        // 4.返回当前对象的hashcode,
        System.out.println(coll.hashCode());
    }
}

1.2 List 接口(Java 1.2)

有序,可重复。“动态数组”;

List 接口是Collection 的一个子接口,所以Collection 中的方法都可以使用,由于List 是有序的,相对与Collection 增加一些索引方法;(Set无序列,所以Collection 不包含索引部分操作)

常用方法:

	public void test01(){
        ArrayList list = new ArrayList();
        list.add("a");
        list.add("b");
        list.add(1);
        list.add(2);
        System.out.println(list); // [a, b, 1, 2]
        // 1.1 添加一个元素
        list.add(2,"c"); 
        System.out.println(list); // [a, b, c, 1, 2]
        // 1.2 添加一组元素
        ArrayList list1 = new ArrayList();
        list1.add(3);
        list1.add(4);
        list.addAll(list);
        System.out.println(list); // [a, b, c, 1, 2, a, b, c, 1, 2]
        // 2.获取
        System.out.println(list.get(0)); // a
        // 3.1 查询 首次出现位置(不存在返回 -1)
        System.out.println(list.indexOf("c")); // 2
        // 3.2 查询 末次出现位置(不存在返回 -1)
        System.out.println(list.lastIndexOf("c")); // 7
        // 4.1 删除 按索引
        Object remove = list.remove(0);
        System.out.println(remove); // 返回被删除的对象 a
        System.out.println(list); // [b, c, 1, 2, a, b, c, 1, 2]
        // 4.1 删除 按对象(基本类型需要转包装类)
        boolean remove1 = list.remove(new Integer(1));
        System.out.println(remove1); // 对象是否删除 true
        System.out.println(list); // [b, c, 2, a, b, c, 1, 2]
        // 5. 修改
        list.set(0,"a");
        System.out.println(list); // [a, c, 2, a, b, c, 1, 2]
        // 6. 获取子集合(左闭又开)
        List list2 = list.subList(1, 5);
        System.out.println(list2); // [c, 2, a, b]
    }

1.2.1 List 实现类 ArrayList(重点 Java 1.2)

ArrayList:List 接口的主要实现类,线程不安全的,执行效率高;底层使用Object[]存储(顺序存储)

JDK 7:初始化时,创建长度为10 的Object 数组;扩容1.5倍;(饿汉式)
建议开发中使用带参的构造器;

JDK 8:初始化为{},赋值时设置长度,没定义长度,赋值时初始长度10;(懒汉式,延迟了数组创建,节省内存)

1.2.2 List 实现类 LinkedList(Java 1.2)

LinkedList:对于频繁的插入和删除操作,效率比ArrayList 效率高;底层使用双向链表(左地址 | 数值 | 右地址)存储

    private static class Node<E> {
        E item;
        Node<E> next;
        Node<E> prev;

        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }

1.2.3 List 实现类 Vector(了解 Java 1.1)

Vector:List 接口的古老实现类,线程安全的,效率低;底层使用Object[]存储

1.3 Set 接口(了解)

无序,不可重复

与List 接口相同,Set 接口也是Connection 的一个子接口;
Set 接口中没有额外定义方法;

1.3.1 Set 实现类 HashSet

Set 接口的主要实现类,线程不安全的,可以存储null 值,实现的是HashMap(),底层为数组;

1)无序性:表现为向底层数组中存值时,不是按照索引顺序存储,而实根据hash 值进行存储;要注意的是,无序性并不表示遍历结果随机输出!

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

hash 值是根据对象属性计算出的值,根据这个值决定在数组中存放的位置,

存放的位置说明
通过散列函数将hash 值映射到数组的索引上,从而将数据存储到指定的索引位置中,当出现索引值相同,但hash 值不同时,再使用链表存储方式进行存储,链表地址指向问题JDK版本不同略有不同(七上八下);若hash 值相同,再进行equals() 方式比较,若返回true 则表名值一样,若返回false 则按照链表存储。
总结:存储对象 ⇒ 计算hash 值 ⇒ 映射索引值 ⇒ 索引处是否为空 ⇒ hash 值是否相同 ⇒ equals() 比较

为什么要重写Set 中添加对象的hashCode() 和equals()
Object 中的hashCode() 是随机计算出的一个值作为内存存放地址,即使内容相同,hash 值却不同,所以要重写hashCode() ;
Object 中的equals() 方法比较的是内存地址,而不是对象内容,所以也要重写;
重写的 hashCode() 和equals() 尽可能保持一致性(自动生成即可),即相等的对象必须具有相等的散列码;

1.3.2 HashSet 的子类LinkedHashSet

在HashSet 基础上,添加数据的同时,在每个数据中添加前后地址(链式),看似有序,遍历时可以按照添加顺序进行遍历;

对于频繁的遍历操作效率高于HashSet;

1.3.3 TreeSet

可以按照添加对象的指定属性进行排序,二叉树存储;
1)TreeSet 中添加的数据要求是相同类的对象(才可能有相同属性);
2)两种排序方式:自然排序(Comparable)、定制排序(Comparator)
注意:若对象中指定的排序对象相同,其他内容不同,也认为两个对象相同,使用时需要注意!

    public void test01(){
        TreeSet treeSet = new TreeSet();
        treeSet.add(5);
        treeSet.add(100);
        treeSet.add(-1);

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

自动排序输出:
-1
5
100

排序对象时,需要对象内部使用比较器(Comparable、Comparator)

    public void test02(){
        TreeSet treeSet = new TreeSet();
        treeSet.add(new User("chengyu",30));
        treeSet.add(new User("zhaoyun",20));
        treeSet.add(new User("liubei",55));

        Iterator iterator = treeSet.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }
class User implements Comparable<User>{
    private String name;
    private int age;
    public User() {
    }
    public User(String name, int age) {
        this.name = name;
        this.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;
    }
    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public int compareTo(User user) {
        return this.name.compareTo(user.name);
        // 可多级排序
    }
}

2. Map 接口(Java 1.2)

双列集合,键值对(key - value)
Map 中的key:无序,不可重复,使用Set 存储;
Map 中的value:无序,可重复,使用Collection 存储;
一个键值对构成了一个Entry 对象,无序,不可重复,使用Set 存储;

2.1 Map 的常用方法

    public void test01(){

        Map map = new HashMap();
        // 1.1 添加(单个元素)
        map.put("A",123);
        map.put("B",456);
        System.out.println(map); // {A=123, B=456}
        // 1.2 添加(Map)
        Map map1 = new HashMap();
        map1.put("C",789);
        map1.put("D",135);
        map.putAll(map1);
        System.out.println(map); // {A=123, B=456, C=789, D=135}
        // 2.修改
        map.put("A",789);
        System.out.println(map); // {A=789, B=456, C=789, D=135}
        // 3.移除
        Object removeValue = map.remove("D");
        System.out.println(removeValue); // 135,移除方法返回的是移除对象的value
        System.out.println(map); // {A=789, B=456, C=789}
        // 4.长度
        System.out.println(map.size()); // 3
        // 5.是否包含指定的Key
        System.out.println(map.containsKey("A")); // true
        // 6.是否包含指定的Value
        System.out.println(map.containsValue(789)); // true
        // 7.清空
        map.clear();
        System.out.println(map); // {}
        // 8.是否为空
        System.out.println(map.isEmpty()); // true
    }

    public void test02(){
        // 遍历
        Map map = new HashMap();
        map.put("A",123);
        map.put("B",456);
        map.put("C",1);
        // 遍历Key
        Set set = map.keySet();
        Iterator iterator = set.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
        // 遍历Vaule
        Collection values = map.values();
        for (Object obj:values) {
            System.out.println(obj);
        }
        // 遍历所有的 Key - Value (方法一)
        Set set1 = map.entrySet();
        Iterator iterator1 = set1.iterator();
        while (iterator1.hasNext()){
            Object next = iterator1.next();
            // Map集合中的元素都是 Entry
            Map.Entry entry = (Map.Entry) next;
            System.out.println(entry.getKey() + " ===> " + entry.getValue());
        }
        // 遍历所有的 Key - Value (方法二)
        Set set2 = map.keySet();
        Iterator iterator2 = set.iterator();
        while (iterator2.hasNext()){
            Object key = iterator2.next();
            Object value = map.get(key);
            System.out.println(key + " ===>>> " + value);
        }
    }

2.2 HashMap(重要 Java 1.2)

Map 的主要实现类,线程不安全的,效率高; 可以存储null 的key 和value;
底层:
数组 + 链表 (jdk1.7及之前)
数组 + 链表 + 红黑树(jdk1.8)

key:无序,不可重复,使用Set 存储,所以存储对象时,要求对象类必须重写equals() 和 hashcode();
value:无序,可重复,使用Collection 存储,所以存储对象时,要求重写
equals() ;

底层实现原理:
jdk 7:数组 + 链表
HashMap map = new HashMap();
实例化后底层创建长度为16 的数组,类型为Entry[] table;
map.put(key1,value1);
首先调用key1 所在类的hashCode(),计算hash 值,次hash 值经过某种计算以后,得到Entry[] 的存放位置,如果此位置有值,比较hash 值,如果hash 值存在相同,调用key1 所在类的equals 方法,返回true,使用value1 替换相同key的value值(覆盖);
注意:数组指定位置为空,线式存储,若有值,进行链式存储!

加载因子(loadFactor):0.75
临界值(threshold):16 * 0.75 = 12,超过此数值时(且要存放的位置不为空),进行2倍扩容;扩容时,进行复制操作,从新计算再存储,原本链式存储也有可能全部变为线式存储,比较消耗资源;

// TODO 看源码

jdk 8:数组 + 链表 + 红黑树
new HashMap(); 时,底层没有创建长度为16 的数组,底层数组为Node类型数组,而非Entry[]
首次调用put() 时,底层创建长度为16 的数组;

当数组某位置上以链表形式存储的数据个数 > 8 且 当前数组长度 > 64 时,次索引位置上的所有数据改为使用红黑树存储;(提升查找速度)

// TODO 看源码

2.3 HashMap 子类LinkedHashMap(了解 Java 1.4)

HashMap 基础上,添加前后地址存储,保证元素可以按照添加时的顺序实现遍历;
对于频繁的遍历操作,效率高于HashMap,除此之外都使用HashMap;

2.4 TreeMap(Java 1.2)

有序的键值对存储
保证按照添加的key-value 对进行排序,实现排序遍历,具体是按照key 进行排序(自然排序或定制排序),所以要求key 必须是由同一个类型创建的对象;底层使用红黑树;

自然排序:

    public void test03(){
        TreeMap treeMap = new TreeMap();
        treeMap.put(new User("chengyu",30),100);
        treeMap.put(new User("zhaoyun",20),50);
        treeMap.put(new User("liubei",55),200);

        Set set1 = treeMap.entrySet();
        Iterator iterator1 = set1.iterator();
        while (iterator1.hasNext()){
            Object next = iterator1.next();
            // Map集合中的元素都是 Entry
            Map.Entry entry = (Map.Entry) next;
            System.out.println(entry.getKey() + " ===> " + entry.getValue());
        }
    }

User{name=‘chengyu’, age=30} ===> 100
User{name=‘liubei’, age=55} ===> 200
User{name=‘zhaoyun’, age=20} ===> 50

定制排序:(根据年龄)

    public void test03(){
        TreeMap treeMap = new TreeMap(new Comparator<User>() {
            @Override
            public int compare(User user1, User user2) {
                return Integer.compare(user1.getAge(),user2.getAge());
            }
        });
        treeMap.put(new User("chengyu",30),100);
        treeMap.put(new User("zhaoyun",20),50);
        treeMap.put(new User("liubei",55),200);

        Set set1 = treeMap.entrySet();
        Iterator iterator1 = set1.iterator();
        while (iterator1.hasNext()){
            Object next = iterator1.next();
            // Map集合中的元素都是 Entry
            Map.Entry entry = (Map.Entry) next;
            System.out.println(entry.getKey() + " ===> " + entry.getValue());
        }
    }

User{name=‘zhaoyun’, age=20} ===> 50
User{name=‘chengyu’, age=30} ===> 100
User{name=‘liubei’, age=55} ===> 200

User 类参照 1.3.3

2.5 Hashtable(Java 1.0)

古老实现类,线程安全,效率低;不可以存储null 的key 和value;

2.6 Hashtable 子类Properties

常用于处理配置文件,key 和value 都是String 类型

	public static void main(String[] args) {
        FileInputStream fls = null;
        try {
            Properties pros = new Properties();
            fls = new FileInputStream("jdbc.properties");
            // 加载文件
            pros.load(fls);
            String name = pros.getProperty("name");
            String password = pros.getProperty("password");
            System.out.println("name=" + name + ",password=" + password); // name=chengyu,password=123456
        }catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(fls != null){
                try {
                    fls.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

3. Collections 类

操作集合的工具类Collection 、Map

常用方法:

    public void test01(){
        List list = new ArrayList();
        list.add(10);
        list.add(4);
        list.add(5);

        System.out.println(list); // [10, 4, 5]
        // 反转
        // Collections.reverse(list); // [5, 4, 10]
        // 随机输出
        // Collections.shuffle(list); // [4, 10, 5]
        // 自然排序(定制排序需要传入Comparator)
        // Collections.sort(list); // [4, 5, 10]
        // 交换
        // Collections.swap(list,1,2); // [10, 5, 4]
        // 最大值、最小值
        // 元素出现的频率
        // int frequency = Collections.frequency(list, 4);
        // System.out.println(frequency); // 1
        // 复制:复制前需要定义一个与元list 等长的list,否则无法复制
        List list1 = Arrays.asList(new Object[list.size()]);
        Collections.copy(list1,list);
        System.out.println(list1); // [10, 4, 5]
        
        // 转线程安全:f返回的list2 即为线程安全
        List list2 = Collections.synchronizedList(list);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值