文章目录
- 一、集合类体系结构
- 二、Collection系列集合
- 2.1 Collection 集合体系
- 2.2 Collection 集合体系特点
- 2.3 Collection 常用API
- 2.4 Collection 集合的遍历方式
- 2.4.1 方式一:迭代器
- 2.4.2 方式二:foreach(增强for循环)
- 2.4.3 方式三:Lambda表达式
- 三、List系列集合
- 3.1 集合特点
- 3.2 集合特有方法
- 3.3 ArrayList 集合
- 3.4 LinkedList集合
- 3.5 遍历方式
- 3.5.1 fori循环
- 3.5.2 迭代器
- 3.5.3 foreach
- 3.5.4 Lambda
- 四、Set 系列集合
- 4.1 集合特点
- 4.2 常用API
- 4.3 哈希表
- 4.4 HashSet 集合
- 4.4.1 存储原理解析
- 4.4.2 去重原理解析
- 4.5 LinkedHashSet 集合
- 4.6 TreeSet集合
- 4.6.1 自定义排序
- 4.6.2 去重原理解析
- 五、Map系列集合
- 5.1 Map 集合体系
- 5.2 Map 集合体系特点
- 5.3 Map 常用API
- 5.4 Map 集合的遍历方式
- 5.5 HashMap
- 5.6 LinkedHashMap
- 5.7 TreeMap
- 5.7.1 自定义排序
- 5.8 去重原理
- 六、不可变集合
一、集合类体系结构
集合分为单列集合与双列集合,其中:
Collection 单列集合,每个元素(数据)只包含一个值。
Map 双列集合,每个元素包含两个值(键值对)。
二、Collection系列集合
2.1 Collection 集合体系
2.2 Collection 集合体系特点
-
List系列集合:添加的元素是有序、可重复、有索引
- ArrayList、LinekdList:有序、可重复、有索引。
-
Set系列集合:添加的元素是无序、不重复、无索引
- HashSet:无序、不重复、无索引。
- LinkedHashSet:有序、不重复、无索引。
- TreeSet:按照大小默认升序排序、不重复、无索引。
-
约定集合存储数据:集合和泛型不支持基本类型,只支持引用数据类型。
注:集合中要存储基本数据类型可以使用包装类。
2.3 Collection 常用API
Collection是单列集合的祖宗接口,它的功能是全部单列集合都可以继承使用的。
示例:
public static void main(String[] args) {
// ArrayList:添加的元素是有序,可重复,有索引。
Collection<String> c = new ArrayList<>();
// 1.添加元素, 添加成功返回true。
c.add("Java");
c.add("HTML");
c.add("HTML");
c.add("MySQL");
c.add("Java");
System.out.println(c); // [Java, HTML, HTML, MySQL, Java]
// 2.清空集合的元素。
// c.clear();
// System.out.println(c);
// 3.判断集合是否为空 是空返回true,反之。
// System.out.println(c.isEmpty());
// 4.获取集合的大小。
System.out.println(c.size());
// 5.判断集合中是否包含某个元素。
System.out.println(c.contains("Java")); // true
System.out.println(c.contains("java")); // false
// 6.删除某个元素:如果有多个重复元素默认删除前面的第一个!
System.out.println(c.remove("Java")); // true
System.out.println(c); // [HTML, HTML, MySQL, Java]
// 7.把集合转换成数组
Object[] arrs = c.toArray();
System.out.println("数组:" + Arrays.toString(arrs)); // 数组:[HTML, HTML, MySQL, Java]
// 注:Arrays工具类的toString方法格式化输出的是数组内容
}
public static void main(String[] args) {
// 拓展 boolean addAll(Collection<? extends E> c) 批量添加
Collection<String> c1 = new ArrayList<>();
c1.add("java1");
c1.add("java2");
Collection<String> c2 = new ArrayList<>();
c2.add("赵敏");
c2.add("殷素素");
// addAll把c2集合的元素全部倒入到c1中去。
c1.addAll(c2);
System.out.println(c1); // [java1, java2, 赵敏, 殷素素]
System.out.println(c2); // [赵敏, 殷素素]
}
2.4 Collection 集合的遍历方式
2.4.1 方式一:迭代器
迭代器在 Java 中的代表是 Iterator,迭代器是集合的专用的遍历方式。
获取迭代器:
Iterator中的常用方法:
示例:
注:lists是多态的定义方式(三种情况都可)
Collection<String> lists = new ArrayList<>();
List<String> lists = new ArrayList<>();
ArrayList<String> lists = new ArrayList<>();
2.4.2 方式二:foreach(增强for循环)
既可以遍历集合也可以遍历数组,基本格式如下:
举例:
注:
由于 List 系列集合有索引,因此也可用常规的 fori 循环遍历。
但由于多态,父类不可调用子类独有功能,因此不可调用子类的 fori 遍历形式,需要强制类型转换。
Set 系列集合没有索引不可用 fori 循环。
修改第三方变量的值不会影响到集合中的对象,但是会影响对象里面的值。
示例1:
Collection<String> lists = new ArrayList<>();
lists.add("赵敏");
lists.add("小昭");
lists.add("殷素素");
for (String ele : lists) {
if(ele.equals("赵敏")){
ele = "新名字";
}
}
System.out.println(lists); // [赵敏, 小昭, 殷素素]
Collection<Student> students = new ArrayList<>();
students.add(new Student("王明", 12));
students.add(new Student("乌戈", 36));
students.add(new Student("李霞", 24));
for (Student student : students) {
if(student.getName().equals("乌戈")){
student = new Student("新来的", 22);
}
}
System.out.println(students);
// [Student{name='王明', age=12}, Student{name='乌戈', age=36}, Student{name='李霞', age=24}]
示例2:
Collection<Student> students = new ArrayList<>();
students.add(new Student("王明", 12));
students.add(new Student("乌戈", 36));
students.add(new Student("李霞", 24));
for (Student student : students) {
if(student.getName().equals("乌戈")){
student.setName("呜呜");
}
}
System.out.println(students);
// [Student{name='王明', age=12}, Student{name='呜呜', age=36}, Student{name='李霞', age=24}]
2.4.3 方式三:Lambda表达式
得益于JDK 8开始的新技术 Lambda 表达式,提供了一种更简单、更直接的遍历集合的方式。
遍历的API:Consumer是一个函数式接口,可通过匿名内部类实现或者子类实现。
示例:
以上形式还可以简化:lists.forEach( System.out::println );
调用流程解析,可参考匿名内部类:
三、List系列集合
3.1 集合特点
ArrayList、LinekdList :有序,可重复,有索引。
- 有序:存储和取出的元素顺序一致
- 有索引:可以通过索引操作元素
- 可重复:存储的元素可以重复
3.2 集合特有方法
注:Collection的功能 List 也都继承了。
示例:
public static void main(String[] args) {
// 1.创建一个ArrayList集合对象:
// List:有序,可重复,有索引的。
List<String> list = new ArrayList<>(); // 一行经典代码!
list.add("Java");
list.add("Java");
list.add("HTML");
list.add("MySQL");
list.add("MySQL");
// 2.在某个索引位置插入元素。
list.add(2, "黑马");
System.out.println(list); // [Java, Java, 黑马, HTML, MySQL, MySQL]
// 3.根据索引删除元素,返回被删除元素
System.out.println(list.remove(1)); // Java
System.out.println(list); // [Java, 黑马, HTML, MySQL, MySQL]
// 4.根据索引获取元素
System.out.println(list.get(1));
// 5.修改索引位置处的元素
System.out.println(list.set(1, "传智教育"));
System.out.println(list); // [Java, 传智教育, HTML, MySQL, MySQL]
}
3.3 ArrayList 集合
ArrayList 底层是基于数组实现的,根据查询元素快,增删相对慢。
3.4 LinkedList集合
LinkedList底层基于双链表实现的,查询元素慢,增删首尾元素非常快。
public static void main(String[] args) {
// LinkedList可以完成队列结构,和栈结构 (双链表)
// 1、做一个队列:
LinkedList<String> queue = new LinkedList<>();
// 入队
queue.addLast("1号");
queue.addLast("2号");
queue.addLast("3号");
System.out.println(queue); // [1号, 2号, 3号]
// 出队
System.out.println(queue.getFirst()); // 1号
System.out.println(queue.removeFirst()); // 1号
System.out.println(queue.removeFirst()); // 2号
System.out.println(queue); // [3号]
// 2、做一个栈
LinkedList<String> stack = new LinkedList<>();
// 入栈 压栈 (push)
stack.push("第1颗子弹"); // push 方法就是 addFirst
stack.push("第2颗子弹");
stack.push("第3颗子弹");
stack.push("第4颗子弹");
System.out.println(stack); // [第4颗子弹, 第3颗子弹, 第2颗子弹, 第1颗子弹]
// 出栈 弹栈 pop
System.out.println(stack.pop()); // pop 方法就是 removeFirst
System.out.println(stack.pop());
System.out.println(stack); // [第2颗子弹, 第1颗子弹]
}
3.5 遍历方式
两种形式都可。
List<String> lists = new ArrayList<>();
List<String> lists = new LinkedList<>();
3.5.1 fori循环
for (int i = 0; i < lists.size(); i++) {
String ele = lists.get(i);
System.out.println(ele);
}
3.5.2 迭代器
Iterator<String> it = lists.iterator();
while (it.hasNext()){
String ele = it.next();
System.out.println(ele);
}
3.5.3 foreach
for (String ele : lists) {
System.out.println(ele);
}
3.5.4 Lambda
lists.forEach(s -> {
System.out.println(s);
});
lists.forEach( System.out::println );
四、Set 系列集合
4.1 集合特点
Set系列集合:添加的元素是无序、不重复、无索引
- HashSet:无序、不重复、无索引。
- LinkedHashSet:有序、不重复、无索引。
- TreeSet:按照大小默认升序排序、不重复、无索引。
没有带索引的方法,所以不能使用普通 fori 循环遍历,也不能通过索引来获取元素。
4.2 常用API
Set 集合的功能上基本上与 Collection 的 API 一致。
4.3 哈希表
4.4 HashSet 集合
特点 : 无序、不重复、无索引
原理:HashSet 集合底层采取哈希表存储的数据。
4.4.1 存储原理解析
JDK8之前的版本,哈希表底层使用数组+链表组成。
JDK8开始后,新元素挂老元素下面,哈希表底层采用数组+链表+红黑树组成。
JDK1.8及以上版本,当挂在元素下面的数据过多时,查询性能降低,从JDK8开始后,当链表长度超过8的时候,自动转换为红黑树。
4.4.2 去重原理解析
参考上方哈希表的创建流程:
① 创建一个默认长度 16,默认加载因为 0.75的数组,数组名 table。
② 根据元素的哈希值跟数组的长度计算出应存入的位置
③ 判断当前位置是否为null,如果是 null 直接存入,如果位置不为 null,表示有元素,
则调用 equals方法比较属性值,如果一样,则不存,如果不一样,则存入数组中该位置的链表。
④ 当数组存满到 16*0.75=12时,就自动扩容,每次扩容原先的两倍。
如果希望 Set 集合认为 2 个内容一样的对象是重复的,必须重写对象的 hashCode() 和 equals() 方法。
示例:构造、set、get 和 toString方法。
public class Student {
private String name;
private int age;
private char sex;
/**
* 重写 equals 方法
* 只要两个对象内容一样,结果一定是true
*/
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age && sex == student.sex && Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age, sex);
}
}
public static void main(String[] args) {
HashSet<Student> sets = new HashSet<>();
Student s1 = new Student("舞阳", 20, '男');
Student s2 = new Student("舞阳", 20, '男');
Student s3 = new Student("周雄", 21, '女');
Student s4 = new Student("王祖", 17, '男');
// 重写 hasCode 方法后,返回的 哈希值相同
System.out.println(s1.hashCode()); // 1029350039
System.out.println(s2.hashCode()); // 1029350039
// 添加集合时候,先判断 hashCode 值,定位哈希表的同一个位置。
// 再通过重写的 equals 方法判断内容是否相等
sets.add(s1);
sets.add(s2);
sets.add(s3);
sets.add(s4);
System.out.println(sets);
// [Student{name='周雄', age=21, sex=女}, Student{name='舞阳', age=20, sex=男}, Student{name='王祖', age=17, sex=男}]
}
4.5 LinkedHashSet 集合
特点:有序、不重复、无索引。有序指的是保证存储和取出的元素顺序一致。
原理:底层数据结构是依然哈希表,只是每个元素又额外的多了一个双链表的机制记录存储的顺序。
示例:
public static void main(String[] args) {
// 有序 不重复 无索引
Set<String> sets2 = new LinkedHashSet<>();
sets2.add("MySql");
sets2.add("MySql");
sets2.add("Java");
sets2.add("Java");
sets2.add("MyBatis");
sets2.add("Html");
sets2.add("Html");
System.out.println(sets2); // [MySql, Java, MyBatis, Html]
}
4.6 TreeSet集合
特点:排序、不重复、无索引。可排序:按照元素的大小默认升序排序。
原理:底层是基于纯红黑树的数据结构实现排序的,增删改查性能都较好。
4.6.1 自定义排序
TreeSet 集合是一定要排序的,可以将元素按照指定的规则进行排序。
默认规则:
① 对于数值类型:Integer、Double,官方默认按照大小进行升序排序。
② 对于字符串类型:默认按照首字符的编号升序排序。
③ 对于自定义类型如Student对象,TreeSet无法直接排序。
自定义排序规则:
方式一: 实现 Comparable 接口重写里面的 compareTo方法来定制比较规则。
方式二:TreeSet 集合有参数构造器,可以设置 Comparator 接口对应的比较器对象,来定制比较规则。
例1:实现 Comparable 接口,重写比较规则。
public class Apple implements Comparable<Apple>{
private String name;
private String color;
private double price;
private int weight;
/**
方式一:实现 Comparable 接口,类自定义比较规则
o1.compareTo(o2)
*/
@Override
public int compareTo(Apple o) {
// 按照重量进行比较的
return this.weight - o.weight ; // 去除 重量 重复的元素
// return this.weight - o.weight >= 0 ? 1 : -1; // 保留 重量 重复的元素
}
}
public static void main(String[] args) {
// 方式一:类自定义比较规则
TreeSet<Apple> apples = new TreeSet<>();
apples.add(new Apple("红富士", "红色", 9.9, 500));
apples.add(new Apple("青苹果", "绿色", 15.9, 300));
apples.add(new Apple("绿苹果", "青色", 29.9, 400));
apples.add(new Apple("黄苹果", "黄色", 9.8, 500));
System.out.println(apples);
// [Apple{name='青苹果', ..., weight=300}, Apple{name='绿苹果', ..., weight=400}, Apple{name='红富士', ..., weight=500}]
}
例2:调用比较器对象的有参构造,进行规则定制。
public static void main(String[] args) {
// 方式二:集合自带比较器对象进行规则定制
TreeSet<Apple> apples2 = new TreeSet<>(new Comparator<Apple>() {
@Override
public int compare(Apple o1, Apple o2) {
return o1.getWeight() - o2.getWeight(); // 升序
// return o2.getWeight() - o1.getWeight(); // 降序
// return Double.compare(o1.getPrice(), o2.getPrice()); // 价格升序
}
});
// Lambda 化简形式
// TreeSet<Apple> apples3 = new TreeSet<>((o1, o2) -> Double.compare(o1.getPrice(), o2.getPrice()));
apples2.add(new Apple("红富士", "红色", 9.9, 500));
apples2.add(new Apple("青苹果", "绿色", 15.9, 300));
apples2.add(new Apple("绿苹果", "青色", 29.9, 400));
apples2.add(new Apple("黄苹果", "黄色", 9.8, 500));
System.out.println(apples2);
// [Apple{name='青苹果', ..., weight=300}, Apple{name='绿苹果', ..., weight=400}, Apple{name='红富士', ..., weight=500}]
}
当两种方式同时出现时采用就近原则,使用匿名内部类的方式,即第二种方式。
注:根据浮点类型变量比较时,一定要使用包装类的 API。
如按照价格升序,价格是 double 类型,return Double.compare(o1.getPrice(), o2.getPrice());
,原因在于两个浮点数相减,再强转成 int 类型( compare 方法返回 int 类型),有可能使得值为 0,如:(int)(5.8-5.8)。
另外,如果价格相同,保留重复的元素,可以采用如下方式:
TreeSet<Apple> apples2 = new TreeSet<>(new Comparator<Apple>() {
@Override
public int compare(Apple o1, Apple o2) {
int compare = Double.compare(o1.getPrice(), o2.getPrice());
return compare>=0 ? 1 : -1; // 价格升序
}
});
例3:倒序排序
TreeSet<Integer> set = new TreeSet<>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});
set.add(2);
set.add(1);
set.add(34);
System.out.println(set); // [34, 2, 1]
4.6.2 去重原理解析
TreeSet 在自定义排序中,重写 equals 方法和 hasCode 方法不会起作用,TreeSet 只走 compareTo 方法。但是可通过设置多重条件来判断属性相同的集合的去重情况。
public class Apple implements Comparable<Apple>{
private String name;
private String color;
private double price;
private int weight;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Apple apple = (Apple) o;
return Double.compare(apple.price, price) == 0 && weight == apple.weight && Objects.equals(name, apple.name) && Objects.equals(color, apple.color);
}
/**
类自定义比较规则
o1.compareTo(o2)
* @param o
* @return
*/
@Override
public int compareTo(Apple o) {
boolean flag = this.equals(o);
if(flag){ // 两个对象成员都相同
return 0; // 去重
}
// 按照重量进行比较的
return this.weight - o.weight ; // 去除 重量 重复的元素
// return this.weight - o.weight >= 0 ? 1 : -1; // 保留重量重复的元素
}
}
public class SetDemo {
public static void main(String[] args) {
// 类自定义比较规则
TreeSet<Apple> apples = new TreeSet<>();
apples.add(new Apple("红富士", "红色", 9.9, 500));
apples.add(new Apple("红富士", "红色", 9.9, 500));
apples.add(new Apple("青苹果", "绿色", 15.9, 300));
apples.add(new Apple("绿苹果", "青色", 29.9, 400));
apples.add(new Apple("黄苹果", "黄色", 9.8, 500));
System.out.println(apples);
// [Apple{name='青苹果', ..., weight=300}, Apple{name='绿苹果', ..., weight=400}, Apple{name='红富士', ..., weight=500}]
}
}
五、Map系列集合
5.1 Map 集合体系
使用最多的Map集合是HashMap,重点掌握HashMap、LinkedHashMap、TreeMap。
5.2 Map 集合体系特点
Map集合是一种双列集合,每个元素包含两个数据,也被称为 “键值对集合”。
Map集合的每个元素的格式:key=value(键值对元素)
Map 集合的完整格式:{key1=value1 , key2=value2 , key3=value3 , ...}
对比 Collection 集合的格式:[元素1,元素2,元素3..]
Map 集合下的实现类的特点都是由键决定。
- HashMap:无序、不重复、无索引
- LinkedHashMap:有序、不重复、无索引。
- TreeMap:不重复、无索引、可排序
5.3 Map 常用API
Map 是双列集合的祖宗接口,它的功能是全部双列集合都可以继承使用的。
public static void main(String[] args) {
// 1.添加元素: 无序,不重复,无索引。
Map<String , Integer> maps = new HashMap<>(); // 一行经典代码
maps.put("iphoneX",10);
maps.put("娃娃",20);
maps.put("iphoneX",100);// Map集合后面重复的键对应的元素会覆盖前面重复的整个元素!
maps.put("huawei",100);
maps.put("生活用品",10);
maps.put("手表",10);
// {huawei=100, 手表=10, 生活用品=10, iphoneX=100, 娃娃=20}
System.out.println(maps);
// 2.清空集合
// maps.clear();
// System.out.println(maps);
// 3.判断集合是否为空,为空返回true,反之为 false
System.out.println(maps.isEmpty());
// 4.根据键获取对应值:public V get(Object key)
Integer value = maps.get("huawei");
System.out.println(value);// 100
System.out.println(maps.get("生活用品2")); // null
// 5.根据键删除整个元素。(删除键会返回键的值)
System.out.println(maps.remove("iphoneX"));
System.out.println(maps);
// 6.判断是否包含某个键 ,包含返回true,反之为 false
System.out.println(maps.containsKey("娃娃")); // true
System.out.println(maps.containsKey("娃娃2")); // false
System.out.println(maps.containsKey("iphoneX")); // false
// 7.判断是否包含某个值。
System.out.println(maps.containsValue(100)); //true
System.out.println(maps.containsValue(10)); //true
System.out.println(maps.containsValue(22)); //false
// {huawei=100, 手表=10, 生活用品=10, 娃娃=20}
// 8.获取全部键的集合:public Set<K> keySet()
Set<String> keys = maps.keySet();
System.out.println(keys); // [huawei, 手表, 生活用品, 娃娃]
// 9.获取全部值的集合:Collection<V> values();
Collection<Integer> values = maps.values();
System.out.println(values); // [100, 10, 10, 20]
// 10.集合的大小
System.out.println(maps.size()); // 4
// 11.合并其他Map集合。(拓展)
Map<String , Integer> map1 = new HashMap<>();
map1.put("java1", 1);
map1.put("java2", 100);
Map<String , Integer> map2 = new HashMap<>();
map2.put("java2", 1);
map2.put("java3", 100);
map1.putAll(map2); // 把集合map2的元素拷贝一份到map1中去
System.out.println(map1); // {java3=100, java2=1, java1=1}
System.out.println(map2); // {java3=100, java2=1}
}
5.4 Map 集合的遍历方式
方式一:先获取Map集合全部的键,再根据遍历键找值
// 1、键找值:第一步:先拿到集合的全部键。
Set<String> keySet = maps.keySet();
// 2、第二步:遍历每个键,根据键提取值
for (String key : keySet) {
Integer value = maps.get(key);
System.out.println(key + "==>" + value);
}
方式二:键值对的方式遍历,把“键值对“看成一个整体,难度较大
// 1、把Map集合转换成Set集合
// 将键和值封装成实体类对象,再将该对象加入到set集合
Set<Map.Entry<String, Integer>> entries = maps.entrySet();
// 2、开始遍历
for (Map.Entry<String, Integer> entry : entries) {
String key = entry.getKey();
Integer value = entry.getValue();
// System.out.println(maps.get(key));
System.out.println(key + "==>" + value);
}
方式三:JDK1.8 开始之后的新技术:Lambda表达式
maps.forEach(new BiConsumer<String, Integer>() {
@Override
public void accept(String key, Integer value) {
System.out.println(key + "--->" + value);
}
});
// Lambda 化简
maps.forEach((k, v) -> {
System.out.println(k + "--->" + v);
});
maps.forEach((k, v) -> System.out.println(k + "--->" + v));
注:底层原理参考 Collection 集合 Lamdba 遍历方式。
5.5 HashMap
特点都是由键决定的:无序、不重复、无索引。
没有额外需要学习的特有方法,直接使用 Map 里面的方法就可以了。
底层实现:Set 系列集合的底层就是 Map 实现的,只是 Set 集合中的元素只要键数据,不要值数据而已。
HashMap 跟 HashSet 底层原理是一模一样的,都是哈希表结构,只是 HashMap 的每个元素包含两个值而已。
5.6 LinkedHashMap
特点都是由键决定:有序、不重复、无索引。有序指的是保证存储和取出的元素顺序一致
底层实现:底层数据结构是依然哈希表,只是每个键值对元素又额外的多了一个双链表的机制记录存储的顺序。
5.7 TreeMap
特点由键决定特性:不重复、无索引、可排序。
可排序:按照键数据的大小默认升序(由小到大)排序,且只能对键排序。
底层实现:TreeMap跟TreeSet一样的,基于红黑树。
5.7.1 自定义排序
方式一:类实现 Comparable 接口,重写比较规则。
public class Apple implements Comparable<Apple>{
private String name;
private String color;
private double price;
private int weight;
/**
方式一:类自定义比较规则
o1.compareTo(o2)
*/
@Override
public int compareTo(Apple o) {
// 按照重量进行比较的
return this.weight - o.weight ; // 去除 重量 重复的元素
// return this.weight - o.weight >= 0 ? 1 : -1; // 保留重量重复的元素
}
}
public static void main(String[] args) {
Map<Apple, String> maps2 = new TreeMap<>();
maps2.put(new Apple("红富士", "红色", 9.9, 500), "山东");
maps2.put(new Apple("青苹果", "绿色", 15.9, 300), "广州");
maps2.put(new Apple("绿苹果", "青色", 29.9, 400), "烟台");
maps2.put(new Apple("黄苹果", "黄色", 9.8, 500), "江西");
System.out.println(maps2);
// {Apple{name='青苹果', ..., weight=300}=广州,
// Apple{name='绿苹果', ..., weight=400}=烟台,
// Apple{name='红富士', ..., weight=500}=江西}
}
方式二:集合自定义 Comparator 比较器对象,调用有参构造,重写比较规则。
public static void main(String[] args) {
Map<Apple, String> appleMap = new TreeMap<>(new Comparator<Apple>() {
@Override
public int compare(Apple o1, Apple o2) {
return o1.getWeight() - o2.getWeight();
}
});
// Map<Apple, String> appleMap2 = new TreeMap<>(( o1, o2) -> o1.getWeight() - o2.getWeight()); // Lambda化简
System.out.println(appleMap);
}
5.8 去重原理
HashMap、LinkedHashMap 去重原理与 Set 集合是相通的,可以通过重写 hasCode 方法和 equals 方法实现,内容相同的对象不可重复添加的效果。
将键和值作为一个整体(Entry对象)的哈希值求余放入数组中,然后通过equals方法对比。
TreeMap底层原理和TreeSet相同,纯红黑树。
六、不可变集合
不可变集合,就是不可被修改的集合。
集合的数据项在创建的时候提供,并且在整个生命周期中都不可改变,否则报错。
注:JDK 9 以后的版本才有不可变集合。
public static void main(String[] args) {
// 1、不可变的List集合
List<Double> lists = List.of(569.5, 700.5, 523.0, 570.5);
// lists.add(689.0); // 报错
// lists.set(2, 698.5); // 报错
double score = lists.get(1);
System.out.println(score);
// 2、不可变的Set集合
Set<String> names = Set.of("迪丽热巴", "迪丽热九", "马尔扎哈", "卡尔眨巴" );
// names.add("三少爷"); // 报错
System.out.println(names);
// 3、不可变的Map集合
Map<String, Integer> maps = Map.of("huawei", 2, "Java开发", 1, "手表", 1);
// maps.put("衣服", 3); // 报错
System.out.println(maps);
}
文章参考:Java入门基础视频教程,java零基础自学就选黑马程序员Java入门教程(含Java项目和Java真题)