可以动态保存任意多个对象;提供了一系列方便操作对象的方法
类别
- 集合主要是两组(单列集合,双列集合)
- 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是线程不安去,且效率高
底层
- ArrayList中维护了一个Object类型的数组elementData
- transient Object[] elementData; // transient表示瞬间,短暂的,表示该属性不会被序列号
- 当创建ArrayList对象时,如果使用的是无参构造器,则初始elementData容量为0,第1次添加,则扩容elementData为10,如需要再次扩容,则扩容elementData为1.5倍
- 如果使用的是指定大小的构造器,则初始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接口
- 无序(添加和取出的顺序不一致),没有索引,因此不能使用索引的方式获取元素
- 不允许重复的元素出现,最多包含一个null
- 取出的顺序是固定的
代码
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
底层机制
- 当向hashset增加一个元素时,会先封装成一个节点Node,再加入table,size会加一
- HashSet的底层是HashMap,
- 第一次添加时,table数组扩容到16,临界值是16*0.75(加载因子loadFactor) = 12 (threshold)
- 当table数组增加的Node的大小 size 到了临界值 12,就会扩容到16 * 2 = 32,新临界值为32*0.75(加载因子) = 24
- 添加一个元素时,会对hash值进行运算,得到一个索引值( - 会转成 -> 索引值)
- 找到存储数据表table,看到这个索引位置是否已经存放的有元素
- 如果没有直接加入
- 如果有,调用equals比较,如果相同,就放弃添加,如果不相同,则添加到最后
- 在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());
}
}
}
常用方法
- put 添加
- remove 根据键删除映射关系
- get 根据键获取值
- size 获取元素个数
- isEmpty 判断个数是否为0
- clear 清除,清空
- containsKey 查找键是否存在
常用遍历方法
- containsKey 查找键是否存在
- keySet 获取所有的键
- entrySet 获取所有关系
- 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],维护数组+双向链表
- 允许重复:List
- 一组键值对 [双列]: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去重.