Day16 Set、比较器
数据结构
- 集合
1.1 Set
无序不可重复
TreeSet : 底层是红黑树(保证元素按照某种顺序排序)
HashSet : 底层是散列
1.1.1 TreeSet
1.1.1.1 概述
java.util.SortedSet
java.util.TreeSet : 会按照某种顺序进行排序
数字 : 从小到大
字符串 : 每位的ASCII
日期 : 自然日期
比较器有两种
要添加的元素实现比较器
专门准备一个比较器类(优先级高)
进行排序的时候,根据比较器方法的返回值进行比较
如果是0 说明重复,不添加,如果是大于0的,说明元素大,往后放
如果是小于0的,说明要添加的元素小,往前放
1.1.1.2 基本使用
public static void main(String[] args) {
//调用TreeSet工具
Set set=new TreeSet();
//add()方法添加数据(每次添加数据都会调用比较器,如果相同就不添加)
set.add(1);
set.add(2);
set.add(2);
set.add(2);
//打印set,且输出结果为 1 2
System.out.println(set);
//删除数据 2
set.remove(2);
System.out.println(set);
set.add(56);
//查找seta中是否含有数据56
System.out.println(set.contains(56));
//打印set长度
System.out.println(set.size());
//清楚set中所有数据
set.clear();
System.out.println(set);
}
1.1.1.3 注意
如果要使用treeSet 那么 元素必须有比较器,两种都可以
否则就会有类型转换异常
1 要添加的原始 实现 java.lang.Comparable接口 并实现compareTo方法
2 写一个比较器类,实现java.util.Comparator比较器接口
很多常用的类中都实现了Comparable接口 并实现compareTo方法
比如 Integer , String , Date等
所以我们自定义类型的时候,一定要弄比较器类
1.1.2 比较器
可以让集合中的元素按照某个规则进行排序
在源码中体现了,先判断是否有compare() 如果没有再判断是否有compareTo()
所以 Comparator优先级要高于Comparable
1.1.2.1 Comparable
也可以叫元素自身比较器,就是要添加的元素需要实现这个接口,一般在我们的自定义类中常用
因为这种方式,直接让要添加的元素类实现接口就可以,编码方便,而Comparator需要单独写比较器类
因为它优先级低,我们给出的排序规则,如果不满足调用处,它还可以根据Comparator进行排序扩展
此时当调用处进行排序扩展的时候,此时Comparator和Comparable同时存在,则Comparator优先级高,所以最终排序规则会按照调用处指定的规则进行排序
public static void main(String[] args) {
Set set=new TreeSet();
set.add(new User(12, “colonel”));
set.add(new User(12, “colonel”));
set.add(new User(13, “colonel”));
set.add(new User(12, “General”));
set.add(new User(12, “colonel”));
System.out.println(set);
}
}
class User implements Comparable{
int age;
String name;
//有参构造方法
public User(int age, String name) {
super();
this.age = age;
this.name = name;
}
@Override
public String toString() {
return "User [age=" + age + ", name=" + name + "]";
}
@Override
public int compareTo(Object o) {
//判断类型是否为 User 的对象,或者是其直接或间接子类,或者是其接口的实现类
if (o instanceof User) {
//强制类型转换
User user=(User) o;
//保存按照年龄排序的结果
int result=age-user.age;
//如果年龄相同,就比较名字,如果名字也相同就不添加
if (result==0) {
if (name.equals(user.name)) {
return 0;
}else {
return 1;
}
}
return result;
}
return 0;
}
1.1.2.2 Comparator
1 该类有排序(比如Integer实现了Comparable,并且是升序),但是排序规则不是我们想要的,这个时候需要使用Comparator来进行调整排序,因为优先级高
2 如果该类没有排序(没有实现Comparable接口),该类也不是我们写的,如果此时需要排序,则需要使用Comparator来完成
public static void main(String[] args) {
//不实现比较器的情况下默认升序排序
Set set =new TreeSet();
set.add(1);
set.add(1);
set.add(12);
set.add(6);
set.add(13);
System.out.println(set);
//传入比较器的情况下按照需求进行排序
Set set1 =new TreeSet(new IntegerCompartor());
set1.add(1);
set1.add(1);
set1.add(12);
set1.add(6);
set1.add(13);
System.out.println(set1);
}
}
class IntegerCompartor implements Comparator{
//实现Comparator 已达到降序的目的
@Override
public int compare(Object o1, Object o2) {
Integer i1=(Integer) o1;
Integer i2=(Integer) o2;
return i2-i1;
}
1.1.3 List排序
static ArrayList list =new ArrayList();
System.out.println(“请输入要添加的数量”);
//接收用户输入的数量
int n=scanner.nextInt();
//动态生成数组的长度
cattle=new Cattle[n];
//创建索引
int index=0;
//如果索引大于等于数量结束循环
creartCattle(n, index);
//根据年龄排序
Collections.sort(list);
//遍历集合
for (Object object : list) {
System.out.println(object);
}
所以 如果保存我们自定义类型,想要排序,必须有一个比较器类
根据需求决定用哪一种即可
1.2 泛型
1.2.1 概述
类型检查,编译过程中检查类型是否匹配
泛型 是在编译阶段对数据的类型进行匹配
优点 : 统一了数据类型,减少强制类型转换
缺点 : 只能存储单一类型的数据
结合我们的需求情况,绝大部分情况都是需要保存统一类型的数据,所以大部分情况下,使用泛型要好很多
泛型 只能是引用类型,不能是基本类型
1.2.2 基本使用
public static void main(String[] args) {
List list = new ArrayList();
list.add(1);
list.add(“xxx”);
List<Integer> nums = new ArrayList<Integer>();
nums.add(11);
// 由于指定了泛型,所以只能保存Integer类型
// nums.add("xx");
list = new ArrayList();
list.add(new A());
list.add(new B());
list.add(new C());
for (Object obj : list) {
if (obj instanceof A) {
A a = (A)obj;
a.m1();
}else if (obj instanceof B) {
B b = (B)obj;
b.m2();
}
}
List<A> as = new ArrayList<A>();
as.add(new A());
for (A a : as) {
a.m1();
}
}
1.2.3 自定义泛型
泛型本质就是一个占位符,由调用处对这个占位符赋值
如果不赋值,默认是Object
常见的占位符 :
? : 表示不确定的类型
T : 表示一个具体的java类型 Type
K : 表示key ,java中的键值对
V : 表示value,
E : 表示Element,元素,集合中的数据我们叫元素
用什么字母都是可以的,一般都是大写,只是占位符而已
自定义泛型
class MyClass{