1. TreeSet特点举例说明
排序: TreeSet
代码在com.stulzl.treeset_.包中
TreeSet_
package com.stulzl.treeset_;
import java.util.Comparator;
import java.util.TreeSet;
//TreeSet特点举例说明 543
@SuppressWarnings({"all"})
public class TreeSet_ {
public static void main(String[] args) {
//解读
//1. 当我们使用无参构造器,创建 TreeSet 时,仍然是无序的
//2. 希望添加的元素,按照字符串大小来排序
//3. 使用 TreeSet 提供的一个构造器,可以传入一个比较器(匿名内部类)
// 并指定排序规则
//4. 简单看看源码
//解读
/*
1. 构造器把传入的比较器对象,赋给了 TreeSet 的底层的 TreeMap 的属性 this.comparator
public TreeMap(Comparator comparator) {
this.comparator = comparator;
}
2. 在 调用 treeSet.add("tom"), 在底层会执行到
if (cpr != null) {//cpr 就是我们的匿名内部类(对象)
do {
parent = t;
//动态绑定到我们的匿名内部类(对象)compare
cmp = cpr.compare(key, t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else //如果相等,即返回 0,这个 Key 就没有加入(也可以理解成替换,因为数据一样嘛,老替新)
return t.setValue(value);
} while (t != null);
}
*/
//如果要求加入的元素,按照长度大小排序
//总结TreeSet之所以可以实现排序,就是因为用户调用有参构造器传了一个比较器compare,如果调用无参
//构造器照样乱序
//使用默认无参构造器,是无序的
//TreeSet treeSet = new TreeSet();
TreeSet treeSet = new TreeSet(new Comparator() {
@Override
public int compare(Object o1, Object o2) {
//将o1,o2向下转型,让后调用String的compareTo方法比较二者的字符串大小
return ((String)o1).compareTo((String)o2);//按字符串大小比较返回
//return ((String)o1).length()-((String)o2).length();//按长度大小比较返回
}
});
//添加数据
treeSet.add("jack");
treeSet.add("tom");
treeSet.add("sp");
treeSet.add("a");
System.out.println("treeSet="+treeSet);
}
}
2. TreeMap源码解析举例 544
会排序
代码在com.stulzl.treemap_.包中
TreeMap_
package com.stulzl.treemap_;
import java.util.Comparator;
import java.util.TreeMap;
//TreeMap源码解析举例 544
@SuppressWarnings({"all"})
public class TreeMap_ {
public static void main(String[] args) {
//使用默认的构造器,创建 TreeMap, 是无序的(也没有排序)
//TreeMap treeMap = new TreeMap();
//使用可以传入比较器的有参构造器
TreeMap treeMap = new TreeMap(new Comparator() {
@Override
public int compare(Object o1, Object o2) {
//要求:按照传入的 k(String) 的大小进行排序
//return ((String)o1).compareTo((String)o2);
//按照 K(String) 的长度大小排序
return ((String)o1).length()-((String)o2).length();
}
});
treeMap.put("jack", "杰克");
treeMap.put("tom", "汤姆");
treeMap.put("kristina", "克瑞斯提诺");
treeMap.put("smith", "斯密斯");
System.out.println("treeMap="+treeMap);
/*
老韩解读源码:
1. 构造器. 把传入的实现了 Comparator 接口的匿名内部类(对象),传给给 TreeMap 的 comparator
public TreeMap(Comparator comparator) {
this.comparator = comparator;
}
2. 调用 put 方法
2.1 第一次添加, 把 k-v 封装到 Entry 对象,放入 root
Entry t = root;
if (t == null) {
compare(key, key);
root = new Entry<>(key, value, null);
size = 1;
modCount++;
return null;
}
2.2 以后添加
Comparator 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 相等,就不添加
return t.setValue(value);
} while (t != null);
}
*/
}
}
3. Collections 工具类 545
3.1 Collections 工具类介绍
1) Collections是一个操作Set. List 和Map等集合的工具类
2) Collections中提供了一系列静态的方法对集合元素进行排序、查询和修改等操作
3.2 Collections操作01:(均为 static 方法) 545
1) reverse(List):反转List中元素的顺序
2) shuffle(List):对List集合元素进行随机排序
3) sort(List):根据元素的自然顺序对指定List集合元素按升序排序
4) sort(List, Comparator): 根据指定的Comparator产生的顺序对List 集合元素进行排序
5) swap(List, int, int): 将指定list集合中的i 处元素和j处元素进行交换
代码在com.stulzl.collections_01.包中
Collections_01
package com.stulzl.collections_01;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
//Collections工具类举例说明01 545
@SuppressWarnings({"all"})
public class Collections_01 {
public static void main(String[] args) {
//创建一个ArrayList集合用于测试
List list = new ArrayList();
list.add("tom");
list.add("smith");
list.add("king");
list.add("milan");
//list.add("tom");
System.out.println("list="+list);
//1) reverse(List):反转List中元素的顺序
Collections.reverse(list);
System.out.println("list="+list);
//2) shuffle(List):对List集合元素进行随机排序
for (int i = 0; i <5; i++) {//使用for循环以展示每次输出的顺序都不一样
Collections.shuffle(list);
System.out.println("list="+list);
}
//3) sort(List):根据元素的自然顺序对指定List集合元素按升序排序
Collections.sort(list);//自然顺序就是abcd……z的ascii码大小
System.out.println("====自然排序后====");
System.out.println("list="+list);
//4) sort(List, Comparator): 根据指定的Comparator产生的顺序对List 集合元素进行排序
//例如我们希望按照字符串的长度大小来排序
System.out.println("====按照字符串的长度大小来排序====");
Collections.sort(list, new Comparator() {//传入匿名内部类比较器
@Override
public int compare(Object o1, Object o2) {
return ((String)o1).length()-((String)o2).length();
}
});
System.out.println("list="+list);
//5) swap(List, int, int): 将指定list集合中的i 处元素和j处元素进行交换
Collections.swap(list,0,1);//即交换第一个和第二个
System.out.println("===交换后===");
System.out.println("list="+list);
}
}
3.3 Collections操作02 546
1) Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素
2) Object max(Collection, Comparator): 根据Comparator指定的顺序,返回给定集合中的最大元素
3) Object min(Collection)
4) Object min(Collection, Comparator)
5) int frequency(Collection, Object): 返回指定集合中指定元素的出现次数
6) void copy(List dest,List src):将src中的内容复制到dest中
7) boolean replaceAll(List list, Object oldVal, Object newVal):使用新值替换List对象的所有旧值
代码在com.stulzl.collections_02.包中
Collections_02
package com.stulzl.collections_02;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
//Collections工具类举例说明02 546
@SuppressWarnings({"all"})
public class Collections_02 {
public static void main(String[] args) {
//创建一个ArrayList集合用于测试
List list = new ArrayList();
list.add("tom");
list.add("smith");
list.add("king");
list.add("milan");
list.add("tom");
System.out.println("list="+list);
//1) Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素
System.out.println("自然顺序的最大值="+ Collections.max(list));//自然顺序的最大值=tom
//2) Object max(Collection, Comparator): 根据Comparator指定的顺序,
// 返回给定集合中的最大元素
//例如按长度最大
Object maxObject = Collections.max(list, new Comparator() {//传入我们的比较器
@Override
public int compare(Object o1, Object o2) {
return ((String)o1).length()-((String)o2).length();
}
});
System.out.println("按长度最大="+maxObject);//按长度最大=smith
//这俩方法和max正好相反
//3) Object min(Collection)
System.out.println("自然顺序的最小值="+ Collections.min(list));//自然顺序的最小值=king
//4) Object min(Collection, Comparator)
Object minObject = Collections.min(list, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
return ((String)o1).length()-((String)o2).length();
}
});
System.out.println("按长度最小="+minObject);//按长度最小=tom
//5) int frequency(Collection, Object): 返回指定集合中指定元素的出现次数
System.out.println("tom出现的次数="+Collections.frequency(list,"tom"));//2
//6) void copy(List dest,List src):将src中的内容复制到dest中
//为了完成一个完整拷贝,我们需要先给 dest 赋值,大小和 list.size()一样
ArrayList dest = new ArrayList();
for (int i=0;i<list.size();i++){//必须保证dest和src大小一样,否则抛出异常
dest.add("");
}
Collections.copy(dest,list);
System.out.println("dest="+dest);
//7) boolean replaceAll(List list, Object oldVal, Object newVal)
// :使用新值替换List对象的所有旧值
Collections.replaceAll(list,"tom","汤姆");
System.out.println("list="+list);
}
}
4.练习
4.1 练习3 549
按要求完成下列任务
1)使用HashMap类实例化一 个Map类型的对象map,键(String) 和值(int) 分别用于存储员工的姓名和工资,存入数据如下:jack—— 650元; tom——1 200元; smith——2900元;
2)将jack的工资更改为2600元
3)为所有员工工资加薪100元;
4)遍历集合中所有的员工
51遍历集合由所有的工资
代码在com.stulzl.exercise03.包中
Exercise03
package com.stulzl.exercise03;
import java.util.*;
//集合练习 549
//按要求完成下列任务
//1)使用HashMap类实例化一 个Map类型的对象map,键(String) 和值(int) 分别用于存储员工的
// 姓名和工资,存入数据如下:jack—— 650元; tom——1200元; smith——2900元;
//2)将jack的工资更改为2600元
//3)为所有员工工资加薪100元;
//4)遍历集合中所有的员工
//5)遍历集合由所有的工资
@SuppressWarnings({"all"})
public class Exercise03 {
public static void main(String[] args) {
Map map = new HashMap();
map.put("jack",650);
map.put("tom",1200);
map.put("smith",2900);
System.out.println(map);
//2)将jack的工资更改为2600元
map.put("tom",2600);
System.out.println(map);
//3)为所有员工工资加薪100元;
//方法1 使用keySet
Set keySet = map.keySet();//单独吧k取出来放到keySet集合中
for (Object o :keySet) {
//更新加100
map.put(o,(Integer)map.get(o)+100);//(Integer)map.get(o) Object->Integer
}
System.out.println(map);
// //方法2 使用entrySet
// Set key = map.entrySet();//将将entry类型转为Map.Entry类型
// for (Object o :key) {
// Map.Entry e = (Map.Entry)o;//要转为Map.Entry方便调用getKey()和getValue()方法
// //(Integer)e.getValue()是Object类型 这个Integer转型,是为了能加100
// map.put(e.getKey(),(Integer)e.getValue()+100);
// }
// System.out.println(map);
//遍历员工
System.out.println("=====遍历员工=====");
Set set = map.entrySet();
Iterator iterator = set.iterator();
while (iterator.hasNext()) {
Map.Entry next = (Map.Entry)iterator.next();//将Entry类型-->Map.Entry
System.out.println(next.getKey());
}
//遍历工资
System.out.println("=====遍历工资=====");
//方法1
Collection values = map.values();//将所有的v取出放在一个集合
// Iterator iterator1 = values.iterator();
// while (iterator1.hasNext()) {
// Object next = iterator1.next();
// System.out.println(next);
// }
//方法2
for (Object o :values) {
System.out.println(o);
}
}
}
4.2 练习4简答题 550
试分析HashSet和TreeSet分别如何实现去重的
(1) HashSet的去重机制: hashCode() + equals()底层先通过存入对象,进行运算得到一个
hash值, 通过hash值得到对应的索引,如果发现table索引所在的位置,没有数据,就直接存放如果有数据,就进行equals比较[遍历比较],如果比较后,不相同,就加入,否则就不加入,
(2) TreeSet的去重机制:如果你传入了一个Comparator匿名对象,就使用实现的compare去
重,如果方法返回0,就认为是相同的元素/数据,就不添加,如果你没有传入一个Comparator
匿名对象,则以你添加的对象实现的Compareable接口的compareTo去重
代码在com.stulzl.exercise04.包中
Exercise04
package com.stulzl.exercise04;
import java.util.TreeSet;
//集合练习 演示TreeSet去重 550
@SuppressWarnings({"all"})
public class Exercise04 {
public static void main(String[] args) {
TreeSet treeSet = new TreeSet();
treeSet.add("hsp");
treeSet.add("tom");
treeSet.add("king");
treeSet.add("hsp");//加入不了
System.out.println(treeSet);
}
}
4.3 练习3 判断输出 550
下面代码运行会不会抛出异常,并从源码层面说明原因[考察读源码+接口编程+动态绑定]
TreeSet treeSet = new TreeSet();
treeSet.add(new Person());
代码在com.stulzl.exercise05.包中
Exercise05
package com.stulzl.exercise05;
import java.util.TreeSet;
//集合练习 550
//下面代码运行会不会抛出异常,并从源码层面说明原因[考察读源码+接口编程+动态绑定]
//TreeSet treeSet = new TreeSet();
//treeSet.add(new Person();
@SuppressWarnings({"all"})
public class Exercise05 {
public static void main(String[] args) {
//分析源码
//add 方法,因为 TreeSet() 构造器没有传入Comparator接口的匿名内部类
//所以在底层调用这个 Comparable k = (Comparable) key;
//即 把 尝试Perosn转成 Comparable类型,因为Person没有实现Comparable接口,所以转不成功
//就会抛出ClassCastException.异常
//TreeSet treeSet = new TreeSet();
//treeSet.add(new Person();
//解决后
TreeSet treeSet = new TreeSet();
treeSet.add(new Person("jack"));//ok
//因为Person重写的compare比较器,只返回了0,并没有写出具体比较依据
treeSet.add(new Person("tom"));//加不进去,
treeSet.add(new Person("july"));//加不进去
System.out.println();
System.out.println(treeSet);//[Person{name='jack'}]
}
}
//class Person{
//
//}
//解决问题 去实现Comparable接口
class Person implements Comparable{
private String name;
public Person(String name) {
this.name = name;
}
//比较器
@Override
public int compareTo(Object o) {
return 0;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
}
4.4 练习6 判断输出 551
下面的代码输出什么?
提示:这道题很有意思,稍不注意就掉进陷阱.
已知: Person类按照id和name重写了hashCode和equals方法,问下面代码输出什么?
代码在com.stulzl.exercise06.包中
Exercise06
package com.stulzl.exercise06;
import java.util.HashSet;
import java.util.Objects;
//集合练习 判断输出 551
//提示:这道题很有意思,稍不注意就掉进陷阱.
//已知: Person类按照id和name重写了hashCode和equals方法,问下面代码输出什么?
@SuppressWarnings({"all"})
public class Exercise06 {
public static void main(String[] args) {
HashSet set = new HashSet();//ok
Person p1 = new Person(1001,"AA");//ok
Person p2 = new Person(1002,"BB");//ok
set.add(p1);//ok
set.add(p2);//ok
p1.name = "CC";
//删除失败,因为之前修改了name为CC,p1(1001 AA)这个老位置不变,
// 但是在计算索引时是按照这个(1001,CC)来计算的 很可能定位不到p1的老索引索引原位置
set.remove(p1);
System.out.println(set);//2个元素
//这个(1001,CC)不会和p1冲突,虽然p1的那么该为CC了,但是也仅仅是修改了值老索引位置不变的
set.add(new Person(1001,"CC"));//ok
System.out.println(set);//3个元素
//这个(1001,"AA"),也不会和p1冲突,因为p1修改了name为CC,他俩的值都不一样
set.add(new Person(1001,"AA"));//ok 挂载到后面
System.out.println(set);//4个元素
}
}
class Person {
public String name;
public int id;
public Person(int id, String name) {
this.name = name;
this.id = id;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return id == person.id &&
Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, id);
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", id=" + id +
'}';
}
}
4.5 练习7 试写出Vector和ArrayList的比较? 551
试写出Vector和ArrayList的比较?