Java面向对象【集合】

可以动态保存任意多个对象;提供了一系列方便操作对象的方法

类别

在这里插入图片描述

  • 集合主要是两组(单列集合,双列集合)
  • Collection 接口下有两个重要的子接口 List和Set,他们的实现子类都是单列集合
  • Map 接口的实现子类 是双列集合,存放的 K-V

体系图

在这里插入图片描述

在这里插入图片描述

collection常用方法

代码

package com.xiaolu.collection_;

import java.util.ArrayList;
import java.util.List;

/**
 * @author 林小鹿
 * @version 1.0
 */
public class CollectionMethod {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
        // 说明:以ArrayList实现类来演示

        List list = new ArrayList();
        // add添加单个元素, 可以针对不同类型自动装箱
        list.add("xiaolu");
        list.add(10);
        list.add(true);
        System.out.println("list=" + list);
        // remove删除指定元素
//        list.remove(0);
//        list.remove("xiaolu");
        // contains查找某个元素是否存在
        System.out.println(list.contains("xiaolu"));
        // size:获取元素个数
        // isEmpty:判断是否为空
        // clear:清空
        // addAll:添加多个元素
        ArrayList list2 = new ArrayList();
        list2.add("三国杀");
        list2.add("火影忍者");
        list.addAll(list2);
        System.out.println("list=" + list);
        // containsAll:查找多个元素是否都存在
        // removeAll:删除多个元素


    }
}

Iterator迭代器

  • Iterator对象称为迭代器,主要用于遍历Collection集合中的元素
  • 所有实现了Collection接口的集合类都有一个Iterator()方法,用于返回一个实现了Iterator接口的对象
  • Iterator仅用于遍历集合,Iterator本身并不存放对象
原理
  • Iterator iterator = coll.iterator() // 得到一个集合的迭代器

  • hasNext():判断是否还有下一个元素

    • while(iterator.hasNext()) {}
    • 快捷键:itit
    • idea 显示所有快捷键的提示键===> ctrl +j
  • next的作用(在调用iterator.next()方法之前必须要调用iterator.hasNext()进检测,否则下一条记录无效)

    • 下移
    • 将下移后集合位置上的元素返回

增强for训练

快捷键:I

增强for训练可以代替iterator迭代器,增强for就是简化版iterator,本质一样,主要用于遍历集合或数组

基本语法

for(元素类型 元素名:集合名或数组名) {

​ 访问元素

}

代码

package com.xiaolu.collection_;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

/**
 * @author 林小鹿
 * @version 1.0
 */
public class CollectionIterator {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
        Collection col = new ArrayList();
        col.add(new Book("口水三国",19.9));
        col.add(new Book("火影忍者",16.1));
        col.add(new Book("Python",21.9));
        // System.out.println("list1=" + col);

        // 1.先得到 col 对应的 迭代器
        Iterator iterator = col.iterator();
        // 2.使用while循环遍历
        // 快速生成while循环快捷键===> itit
        // 显示所有快捷键的提示键===> ctrl +j
        while (iterator.hasNext()) {// 判断是否还有数据
            // 返回下一个元素,类型是Object
            Object obj = iterator.next();
            System.out.println("obj=" + obj);
        }
        // 3.当退出while循环后,这时iterator迭代器,指向i最后的元素
        // 4.如果希望再次遍历,需要复位重置我们的迭代器
        iterator = col.iterator();
        System.out.println("第二次遍历");
        while (iterator.hasNext()) {
            Object obj = iterator.next();
            System.out.println("obj=" + obj);
        }

        System.out.println("增强for");
        // 增强for
        for (Object book :
                col) {
            System.out.println("book=" + book);
        }

    }
}

class Book {
    private String name;
    private double prices;

    public Book(String name, double prices) {
        this.name = name;
        this.prices = prices;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getPrices() {
        return prices;
    }

    public void setPrices(double prices) {
        this.prices = prices;
    }

    @Override
    public String toString() {
        return "Book{" +
                "name='" + name + '\'' +
                ", prices='" + prices + '\'' +
                '}';
    }
}

List接口

  • List集合类中元素有序,且可重复
  • List集合中的每个元素都有对应的顺序索引,即支持索引
常用方法
package com.xiaolu.list_;

import java.util.ArrayList;
import java.util.List;

/**
 * @author 林小鹿
 * @version 1.0
 */
public class List_ {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add("张三丰");
        list.add("贾宝玉");

        // 在index = 1的位置上插入一个对象
        list.add(1, "林小鹿");
        List list2 = new ArrayList();
        list2.add("jack");
        list2.add("tom");
        list.addAll(1, list2);
        System.out.println("list=" + list);
        // Object get(int index):获取指定index位置的元素
        System.out.println(list.get(1));
        // int indexOf(Object obj):返回obj在集合中首次出现的位置
        System.out.println(list.indexOf("tom"));
        // int lastindexOf(Object obj):返回obj在当前集合中末次出现的位置
        // Object remove(int index):移除指定index位置的元素,并返回此元素
        // Object set(int index, Object ele):设置指定index位置元素为ele,相当于替换
        list.set(1, "小米");
        System.out.println("list=" + list);
        // List subList(int fromIndex, int toIndex):返回从fromIndex到toIndex位置的子集合(前闭后开),相当于切片
        List relist = list.subList(0, 2);
        System.out.println("relist=" + relist);


    }
}
案例
package com.xiaolu.list_;

import java.util.*;

/**
 * @author 林小鹿
 * @version 1.0
 */
@SuppressWarnings({"all"})
public class ListExercise {

    public static void main(String[] args) {
        List list = new ArrayList();
        list.add(new Book("book01", "author01", 100));
        list.add(new Book("book02", "author02", 10));
        list.add(new Book("book03", "author03", 12));
        list.add(new Book("book04", "author04", 80));
        list.add(new Book("book05", "author05", 52));


        // 遍历
        Iterator iterator = list.iterator();
        while (iterator.hasNext()) {
            Object obj = iterator.next();
            System.out.println(obj);
        }
        // 对集合进行冒泡排序
        sort(list);
        System.out.println("==排序后==");
        for (Object o :list) {
            System.out.println(o);
        }


    }

    // 静态方法
    // 要求价格从小到大排序
    public static void sort(List list) {
        int size = list.size();
        for (int i = 0; i < size - 1; i++) {
            for (int j = 0; j < size - 1 - i; j++) {
                // 取出object对象并通过向下转型转成Book对象
                Book book01 = (Book) list.get(j);
                Book book02 = (Book) list.get(j + 1);
                if (book01.getPrice() > book02.getPrice()) {// 交换
                    list.set(j, book02);
                    list.set(j + 1, book01);
                }

            }
        }


    }

}

ArrayList

  • 可以放入任何值,并且可以放多个null
  • ArrayList是由数组来实现数据储存的
  • 基本等同于Vector,但ArrayList是线程不安去,且效率高

底层

  1. ArrayList中维护了一个Object类型的数组elementData
    • transient Object[] elementData; // transient表示瞬间,短暂的,表示该属性不会被序列号
  2. 当创建ArrayList对象时,如果使用的是无参构造器,则初始elementData容量为0,第1次添加,则扩容elementData为10,如需要再次扩容,则扩容elementData为1.5倍
  3. 如果使用的是指定大小的构造器,则初始elementData容量为指定大小,如果需要扩容,则直接扩容elementData为1.5倍

Vector

  • 底层也是一个对象数组,protected Object[] elementData;

  • Vector 是线程同步,即线程安全,方法带有synchronized

  • 扩容

    • 默认10,满后按2倍扩容
    • 如果指定大小,则每次直接按2倍扩容

LinkedList

  • LinkedList底层实现了双向链表和双端队列特点

  • 可以添加任意元素(元素可重复)

  • 线程不安全

  • 底层操作机制

    • LinkedList维护了两个属性first和last分别指向首节点和尾节点
    • 每个节点(Node对象),里面又维护了prev、next、item三个属性,其中通过prev指向前一个,通过next指向后一个节点
    • 添加和删除,不是通过数组完成的,效率相对较高

ArrayList和LinkedList

  • 如果改查操作多,选择ArrayList
  • 如果增删LinkedList
  • 一般,大部分操作都是查询,一般是选择ArrayList,可根据具体的业务需求灵活选择

Set接口

  1. 无序(添加和取出的顺序不一致),没有索引,因此不能使用索引的方式获取元素
  2. 不允许重复的元素出现,最多包含一个null
  3. 取出的顺序是固定的

代码

package com.xiaolu.set_;

import java.util.HashSet;
import java.util.Iterator;

/**
 * @author 林小鹿
 * @version 1.0
 */
public class SetMethod {

    @SuppressWarnings({"all"})
    public static void main(String[] args) {
        // set 接口的实现类的对象,不能存放重复的元素,可添加null
        // set 接口对象存放数据是无序的
        HashSet hashSet = new HashSet();
        hashSet.add("jack");
        hashSet.add(null);
        hashSet.add("john");
        hashSet.add("jack");
        hashSet.add("amy");
        System.out.println(hashSet);

        // 遍历方式
        // 1:迭代器
        System.out.println("===========迭代器=============");
        Iterator iterator = hashSet.iterator();
        while (iterator.hasNext()) {
            Object obj = iterator.next();
            System.out.println(obj);
        }
        hashSet.remove("amy");
        // 2.增强for
        System.out.println("==========增强for=========");
        for (Object o : hashSet) {
            System.out.println(o);
        }

        // 无法通过普通for循环,通过索引来获取

    }
}

HashSet

  • 实现类Set接口
  • HashSet的底层是HashMap
  • 节点 Node
    • value
    • key
    • hash
    • next
底层机制
  1. 当向hashset增加一个元素时,会先封装成一个节点Node,再加入table,size会加一
  2. HashSet的底层是HashMap,
    • 第一次添加时,table数组扩容到16,临界值是16*0.75(加载因子loadFactor) = 12 (threshold)
    • 当table数组增加的Node的大小 size 到了临界值 12,就会扩容到16 * 2 = 32,新临界值为32*0.75(加载因子) = 24
  3. 添加一个元素时,会对hash值进行运算,得到一个索引值( - 会转成 -> 索引值)
  4. 找到存储数据表table,看到这个索引位置是否已经存放的有元素
  5. 如果没有直接加入
  6. 如果有,调用equals比较,如果相同,就放弃添加,如果不相同,则添加到最后
  7. 在java8中,如果一条链表的元素个数超过 TREEIFY_THRESHOLD(默认是 8),并且table的大小 >= MIN_TREEIFY_CAPACITY(默认64),就会进行树化(红黑树),否则仍然采用数组扩容机制

LinkedHashSet

加入数据和取出数据顺序一致,且不重复

  • LinkedHashSet 是 HashSet 的子类
  • LinkedHashSet 底层是一个 LinkedHashMap(是HashMap的子类),底层维护了一个 数组 + 双向链表
  • LinkedHashSet 根据元素的 hashCode 值来决定元素的存储位置,同时使用链表维护元素的次序,这使得元素看起来是以插入顺序保存的
  • LinkedHashSet 不允许添重复元素
底层
  • 在 LinkedHashSet 中维护了一个hash表和双向链表(LinkedHashSet 有 head 和 tail)
  • 每一个节点有 before 和 after 属性,这样可以形成双向链表
  • 在添加一个元素时,先求hash值,再求索引,确定该元素在table的位置,然后将添加的元素加入到双向链表(如果已经存在,不添加[原则和hashset一样])
  • 这样的话,我们遍历LinkedHashSet 也能确保插入顺序和遍历顺序一致

Map接口

Map存放的数据为一对k-v,是放在一个HashMap$Node中的,又因为Node实现了 Entry接口,故一对k-v就是一个Entry,实用性比较高

  • Map与Collection并列存在。用于保存具有映射关系的数据:Key-Value(双列元素)
  • Map 中的 key 和 value key是任何引用类型的数据,会封装到HashMap$Node 对象中
  • Map 中的 key 不允许重复,原因和HashSet 一样,但是value可以重复
    • 当有相同的k时,就等价于替换
  • Map的 key为 null,value 也可以为 null,但是key 为null 只能有一个,value可有多个
  • 常用String类作为Map的 key
  • 通过get 方法,传入 key ,会返回得到对应的value;通过put进行添加key-value
补充

table里头存放 k-v ,为了方便遍历,将其取出,放到Entry中,再放到EntrySet集合中,而key是放在EntrySet中的Set集合,value是放在EntrySet中的Collection集合中

  • k-v 最后是 HashMap$Node node = newNode(hash,key,value,null) 出来的
  • k-v 为了方便程序员遍历,还会 创建 EntrySet 集合,该集合存放的元素的类型 Entry,而一个 Entry 对象就有k,v EntrySet<Entry<k,v>> 即: transient Set<Map.Entry<k,v>> entrySet;
  • EntrySet 里头存放的还是Node。entrySet中定义类型是 Map.Entry,但是实际存放的还是 HashMap$Node(为什么EntrySet可以存放Node)这是因为 Node实现了 Entry (static class Node<k,v> implements Map.Entry<k,v>)
  • 当把 HashMap$Node 对象 存放到 entrySet 就方便我们的遍历
小结
  • HashMap是Map 接口使用频率最高的实现类
  • 以key-val 对的方式来存储数据(HashMap$Node类型)
  • 允许使用null
  • 添加相同的key则会覆盖(key不会替换,val会替换)
  • 与HashSet一样,不保证映射顺序,因为底层是以hash表的方式来存储
  • HashMap没有实现同步,因此是线程不安全的,方法没有做同步互斥的操作,没有关键字synchronized
代码
package com.xiaolu.map_;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * @author 林小鹿
 * @version 1.0
 */
@SuppressWarnings({"all"})
public class MapSource_ {

    public static void main(String[] args) {

        Map map = new HashMap();
        map.put("no1", "林小鹿");  // k-v
        map.put("no2", "陈晓霞");  // k-v
        map.put("no1", "林晓霞");  // k-v

        // - k-v 最后是 HashMap$Node node = newNode(hash,key,value,null)
        //- k-v 为了方便程序员遍历,还会 创建 EntrySet 集合,该集合存放的元素的类型 Entry,而一个 Entry 对象就有k,v EntrySet<Entry<k,v>> 即: transient Set<Map.Entry<k,v>> entrySet;
        //- EntrySet 里头存放的还是Node。entrySet中定义类型是 Map.Entry,但是实际存放的还是 HashMap$Node(为什么EntrySet可以存放Node)这是因为 Node实现了 Entry  (static class Node<k,v> implements Map.Entry<k,v>)
        //- 当把 HashMap$Node 对象 存放到 entrySet 就方便我们的遍历
        // K getKey(); V getValue();
        Set set = map.entrySet();
        System.out.println(set.getClass());
        for (Object obj : set) {
            System.out.println(obj.getClass());

            // 从HashMap$Node 取出k-v
            // 先做一个向下转型
            Map.Entry entry = (Map.Entry) obj;
            System.out.println(entry.getKey() + "-" + entry.getValue());

        }


    }

}
常用方法
  1. put 添加
  2. remove 根据键删除映射关系
  3. get 根据键获取值
  4. size 获取元素个数
  5. isEmpty 判断个数是否为0
  6. clear 清除,清空
  7. containsKey 查找键是否存在
常用遍历方法
  1. containsKey 查找键是否存在
  2. keySet 获取所有的键
  3. entrySet 获取所有关系
  4. values 获取所有的值
代码
package com.xiaolu.map_;

import java.util.*;

/**
 * @author 林小鹿
 * @version 1.0
 */
@SuppressWarnings({"all"})
public class MapFor_ {

    public static void main(String[] args) {
        // 遍历
        Map map = new HashMap();
        map.put("no1", "林小鹿");  // k-v
        map.put("no2", "陈晓霞");  // k-v
        map.put("no1", "林晓霞");  // k-v
        map.put(null, "林晓霞");  // k-v

        // 第一组:先取出 所有的key,通过key 取出对应的Value
        Set keyset = map.keySet();
        // (1) 增强for
        System.out.println("=====方式①=====");
        for (Object key : keyset) {
            System.out.println(key + "-" + map.get(key));
        }

        // (2)迭代器
        System.out.println("=====方式②=====");
        Iterator iterator = keyset.iterator();
        while (iterator.hasNext()) {
            Object key = iterator.next();
            System.out.println(key + "-" + map.get(key));
        }

        // 第二组:把所有的value取出
        Collection values = map.values();
        // (1)、增强for
        // (2)、迭代器

        System.out.println("第三组 通过EntrySet 来获取 k-v");
        // 第三组: 通过EntrySet 来获取 k-v
        Set entrySet = map.entrySet();  // entrySet集合里面放了Map.Entry ==>  EntrySet<Entry<k,v>>
        // (1) 增强for
        for (Object entry : entrySet) {
            // 由于entrySet集合里面放了Map.Entry,因此需要先向下转型
            Map.Entry m = (Map.Entry) entry;
            System.out.println(m.getKey() + "-" + m.getValue());
        }
        // (2) 迭代器
        Iterator iterator1 = entrySet.iterator();
        while (iterator1.hasNext()) {
            Object entry = iterator1.next();
            System.out.println(entry.getClass());  // HashMap$Node --实现了 Map.Entry接口,因此可以先转成 Map.Entry再调用 getKey() 和 getValue()
            Map.Entry m = (Map.Entry) entry;
            System.out.println(m.getKey() + "-" + m.getValue());
        }


    }


}
实例
package com.xiaolu.map_;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 * @author 林小鹿
 * @version 1.0
 */
@SuppressWarnings({"all"})
public class MapExercise01 {

    public static void main(String[] args) {

        Map hashMap = new HashMap();
        hashMap.put(301, new Employee("小红",301,1900));
        hashMap.put(302, new Employee("小花",302,8000));
        hashMap.put(303, new Employee("小绿", 303, 1010));
        System.out.println("========遍历一======");
        Set set = hashMap.keySet();
        for (Object key : set) {
            Employee per01 = (Employee) hashMap.get(key);
            if (per01.getSalary() >= 1800) {
//                System.out.println(key + "=" + hashMap.get(key));
                System.out.println(per01);
            }
        }
        System.out.println("++++++++++++++");

        Iterator iterator = set.iterator();
        while (iterator.hasNext()) {
            Object key = iterator.next();
            System.out.println(key+"="+hashMap.get(key));

        }

        System.out.println("========遍历二======");

        Set entrySet = hashMap.entrySet();
        for (Object entry : entrySet) {
            Map.Entry m = (Map.Entry) entry;
            System.out.println(m.getKey()+"="+m.getValue());

        }
        System.out.println("++++++++++++++");
        Iterator iterator1 = entrySet.iterator();
        while (iterator1.hasNext()) {
            Map.Entry entry = (Map.Entry) iterator1.next();
            Employee per02 = (Employee) entry.getValue();
            if (per02.getSalary() >= 1800) {
//                System.out.println(m.getKey() + "=" + m.getValue());
                System.out.println(per02);
            }
        }

    }


}

class Employee {
    private String name;
    private int id;
    private double salary;

    public Employee(String name, int id, double salary) {
        this.name = name;
        this.id = id;
        this.salary = salary;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", id=" + id +
                ", salary=" + salary +
                '}';
    }
}
HashMap底层机制
扩容机制与HashSet相同
  • HashMap底层维护了Node类型的数组table,默认为null
  • 当创建对象时,将加载因子(loadfactor)初始化为0.75
  • 当添加key-val时,通过key的哈希值得到在table的索引。然后判断该索引处是否有元素,如果没有元素直接添加。如果该索引处有元素,继续判断该元素的key是否和准备加入的key相等。如果添加时发现容量不够,则需要扩容
  • 第一次添加,则需要扩容table容量为16,临界值(threshold)为12(16*0.75)
  • 以后再扩容,则需要扩容table容量为原来的2倍,临界值为原来的2倍,即24,一次类推。
  • 在JAVA8中,如果一条链表的元素个数超过TREEIFY_THRESHOLD(默认是8),并且table的大小 >= MIN_TREEIFY_CAPACITY(默认64),就会进行树化(红黑树)
HashTable类(Map接口实现类)
  • 存放的元素时键值对:即 k-v
  • hashTable的键和值都不能为null
  • hashTable 使用方法基本和HashMap一样
  • hashTable 是线程安全的,hashMap 是线程不安全的,但效率比 hashMap 低
底层
  • 底层偶遇数组Hashtable$Entry[] 初始化大小为11
  • 临界值(threshold为8=11*0.75)
  • 每次扩容值 = 原大小 * 2 + 1
Properties类(Map接口实现类)
  • Properties类继承自Hashtable类并且实现类Map接口,也是使用一种键值对的形式来保存数据
  • 他的使用特点和Hashtable类似
  • Properties还可以用于 从 xxx.properties 文件中,加载数据到Properties类对象,并进行读取和修改
  • 工作中 xxx.properties 文件通常作为配置文件
代码
package com.xiaolu.map_;

import java.util.Properties;

/**
 * @author 林小鹿
 * @version 1.0
 * Properties**还可以用于 从 xxx.properties 文件中,加载数据到Properties类对象,并进行读取和修改
 * 工作中 xxx.properties 文件通常作为配置文件
 */
@SuppressWarnings({"all"})
public class Properties_ {

    public static void main(String[] args) {

        // Properties 继承 Hashtable
        // 可以通过k-v 存放数据 ,但不能为null

        Properties properties = new Properties();

        // 增加
        properties.put("john", 100); // k-v
        properties.put("lucy", 150);
        properties.put("aohn", 70);
        properties.put("john", 10);  // 替换
        properties.put("bohn", 80);

        System.out.println("properties=" + properties);

        // 查:通过k 获取对应值
        System.out.println(properties.get("lucy"));
        System.out.println(properties.getProperty("lucy"));

        // 删除
        properties.remove("aohn");
        System.out.println("properties=" + properties);

        // 修改
        properties.put("john", "林校路");  // 原理:替换
        System.out.println("properties=" + properties);


    }

}

使用场景

主要取决于业务操作特点

  • 判断存储类型
  • 一组对象[单列]:Collection接口
    • 允许重复:List
      • 增删多:LinkedList [底层维护了一个双向链表]
      • 查改多:ArrayList [底层维护 Object 类型的可变数组]
    • 不允许重复:Set
      • 无序:HashSet [底层是HashMap,维护了一个哈希表 即(数组+链表+红黑树)]
      • 排序:TreeSet
      • 插入和取出顺序一致:LinkedHashSet [底层是LinkedHashMap,再底层是HashMap],维护数组+双向链表
  • 一组键值对 [双列]:Map接口
    • 键无序:HashMap [底层是:哈希表 jdk7:数组+链表;jdk8 :数组+链表+红黑树]
    • 键排序:TreeMap
    • 键插入和取出顺序一致:LinkedHashMap
    • 读取文件 : Properties

TreeSet

特点:可定义排序,底层为TreeMap

代码

package com.xiaolu.set_;

import java.util.Comparator;
import java.util.TreeSet;

/**
 * @author 林小鹿
 * @version 1.0
 */
@SuppressWarnings({"all"})
public class TreeSet_ {

    public static void main(String[] args) {

        // 当使用无参构造器时,创建TreeSet时,仍然是无序的
        // 若想顺序排序,可使用TreeSet 提供的一个构造器,可以传入一个比较器(匿名内部类),并指定排序规则

//        TreeSet treeSet = new TreeSet();
        TreeSet treeSet = new TreeSet(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                // 下面 调用String的 Comparator方法紧系字符串大小的比较
//                return ((String) o1).compareTo((String) o2);

                // 如果按加入的元素的大小长度来排,则
                return ((String) o1).length() - ((String) o2).length();

            }
        });
        // 添加数据
        treeSet.add("jack");
        treeSet.add("maki");
        treeSet.add("s");
        treeSet.add("a");

        System.out.println("treeSet=" + treeSet);


    }
}

/*
底层走的是TreeMap的源码,因此当 cmp = 0 时,不添加元素
Comparator<? super K> cpr = comparator;
        if (cpr != null) {
            do {
                parent = t;
                cmp = cpr.compare(key, t.key);
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else {
                    V oldValue = t.value;
                    if (replaceOld || oldValue == null) {
                        t.value = value;
                    }
                    return oldValue;
                }
            } while (t != null);
 */

TreeMap

与TreeSet的区别:为键值对,值可变

代码

package com.xiaolu.set_;

import java.util.Comparator;
import java.util.TreeSet;

/**
 * @author 林小鹿
 * @version 1.0
 */
@SuppressWarnings({"all"})
public class TreeSet_ {

    public static void main(String[] args) {

        // 当使用无参构造器时,创建TreeSet时,仍然是无序的
        // 若想顺序排序,可使用TreeSet 提供的一个构造器,可以传入一个比较器(匿名内部类),并指定排序规则

//        TreeSet treeSet = new TreeSet();
        TreeSet treeSet = new TreeSet(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                // 下面 调用String的 Comparator方法紧系字符串大小的比较
//                return ((String) o1).compareTo((String) o2);

                // 如果按加入的元素的大小长度来排,则
                return ((String) o1).length() - ((String) o2).length();

            }
        });
        // 添加数据
        treeSet.add("jack");
        treeSet.add("maki");
        treeSet.add("s");
        treeSet.add("a");

        System.out.println("treeSet=" + treeSet);


    }
}

/*
1、底层走的是TreeMap的源码,因此当 cmp = 0 时,不添加元素
Comparator<? super K> cpr = comparator;
        if (cpr != null) {
            do {
                parent = t;
                cmp = cpr.compare(key, t.key);
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else {
                    V oldValue = t.value;
                    if (replaceOld || oldValue == null) {
                        t.value = value;
                    }
                    return oldValue;
                }
            } while (t != null);

2、调用put方法
2.1 第一次添加,只有一个元素,调用不了比较器
    把k-v 封装到 Entry对象,放入root中
Entry<K,V> t = root;
        if (t == null) {
            addEntryToEmptyMap(key, value);
            return null;
        }
2.2 第二次添加,调用比较器
Comparator<? super K> cpr = comparator;   // 比较器
        if (cpr != null) {
            do {  // 遍历所有的key,给当前key找适当位置 挂上去
                parent = t;
                cmp = cpr.compare(key, t.key);  // 动态绑定到我们的匿名内部类的compare方法
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else {  // 如果遍历过程中,发现准备添加key 和当前已有的key 相等,就直接返回不添加
                    V oldValue = t.value;
                    if (replaceOld || oldValue == null) {
                        t.value = value;
                    }
                    return oldValue;
                }
            } while (t != null);

 */

Collections工具类

是一个操作Set、List和Map 等集合的工具类

提供了一系列静态的方法对集合元素进行排序、查询和修改等操作

排序操作:(static方法)

  • 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 oldVal, Object newVal):使用新值替换 List 对象的所有旧值

试分析HashSeti和TreeSets分别如何实现去重的

  • HashSet的去重机制:hashCode0+equals(0,底层先通过存入对象(key),进行运算得到一个hash值,通过hash值得到对应的索引,如果发现table索引所在的位置,没有数据,就直接存放,如果有数据,就进行equals比较[遍历比较],如果比较后,不相同,就加入,否则就不加入.
  • TreeSet的去重机制:如果你传入了一个Comparator匿名对象,就使用实现的compare去重,如果方法返回0,就认为是相同的元素/数据,就不添加,如果你没有传入一个Comparator匿名对象,则以你添加的对象实现的Compareable:接口的compareTo去重.
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

進擊的小鹿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值