set
// 特点
// 不包含重复元素,由于他不能直接实例化
// 一般情况 使用子类实例化 hashset TreeSet
// HashSet集合
// 元素唯一的存储和取出不一致(无序),不保证顺序恒久不变
// 使用set集合存储字符串元素
package set;
import java.util.HashSet;
import java.util.Set;
public class SetDemo1 {
public static void main(String[] args) {
Set<String>set=new HashSet<String>();
//给集合中添加元素
//唯一 自己去重
set.add("李小龙");
set.add("成龙");
set.add("周星驰");
set.add("刘德华");
set.add("李小龙");
set.add("成龙");
//增强for
for(String s:set) {
System.out.println(s);
}
}
周星驰
成龙
李小龙
刘德华
//去掉重复
//顺序不一致
}
//使用set集合存储自定义对象时Student类型(成员变量内容一样)
//认为是同一个人
//存储的是自定义对象,
HashSet
//HashSet集合底层add依赖于HashMap的put
//依赖于HashCode和equals()方法
//haseCode 保证唯一性(比较对象的地址值是否相同,
//如果地址值相同,还需要比较内容是否相同)
//equals():默认比较的地址值相同,要比较内容是否相同,
//必须在当前类中重写equals()方法
//set集合去重特性就是以上
import java.util.HashSet;
import java.util.Set;
public class SetDemo2 {
public static void main(String[] args) {
//建立一个set集合对象
Set<Student> set=new HashSet<Student>();
//创建学生对象
Student s1 = new Student("中国", 20) ;
Student s2 = new Student("日本", 18) ;
Student s3 = new Student("日本", 18) ;
Student s4 = new Student("韩国", 25) ;
Student s5 = new Student("韩国", 25) ;
Student s6 = new Student("越南", 27) ;
Student s7 = new Student("越南", 27) ;
//给集合中添加
set.add(s1) ;
set.add(s2) ;
set.add(s3) ;
set.add(s4) ;
set.add(s5) ;
set.add(s6) ;
set.add(s7) ;
//遍历
for(Student s: set) {
System.out.println(s.getName()+"---"+s.getAge());
}
}
}
在用set存储自定义对象时
没有重写hashcode和equals会
日本—18
越南—27
越南—27
韩国—25
中国—20
日本—18
韩国—25
没有去重
重写后
越南—27
中国—20
日本—18
韩国—25
可以看到 顺序还是不能保障的
为什么Set集合存储的都是唯一的?
因为他的add() 添加方法
add()依赖于HashCode和equals
先比较哈希码值 值一样在比较内容 两个都一样就判定相等
String类型自动重写了
LinkedHashSet:
底层依赖于哈希表和链接列表实现
由哈希表保证元素唯一
由链表保证元素有序
特点:有序性和唯一性
Treeset集合:
// 基于TreeMap的实现 底层数据结构 根据不同的构造方法
//进行排序
//我的理解 既唯一 又可以自己构造排序
//排序两种方式 自然排序 构造器排序
自然排序
package set;
import java.util.Set;
import java.util.TreeSet;
public class TreeSetDemo1 {
public static void main(String[] args) {
//创建一个TreeSet集合对象
Set<Integer> set=new TreeSet<Integer>();
//添加元素
set.add(20) ;
set.add(18) ;
set.add(23) ;
set.add(22) ;
set.add(17) ;
set.add(24) ;
set.add(19) ;
set.add(18) ;
set.add(24) ;
//遍历集合
for(Integer vv:set) {
System.out.println(vv);
}
}
17
18
19
20
22
23
24
}
这是因为Integer里面继承了自然排序 于是就有小到大排列了(默认升序)
再看TreeSet集合和自定义类
方式: 在子实现类重写Comparable
测试类
import java.util.TreeSet;
public class TreeSetDemo2 {
public static void main(String[] args) {
//创建Treeset集合对象
TreeSet<Student> ss=new TreeSet<Student> ();
//创建学生对象
Student s1=new Student("张国荣",5);
Student s2=new Student ("张杰",6);
Student s3=new Student ("李",7);
Student s4=new Student("樱木花道",8);
Student s5=new Student ("迈克尔杰克逊",8);
//添加
ss.add(s1) ;
ss.add(s2) ;
ss.add(s3) ;
ss.add(s4) ;
ss.add(s5) ;
//遍历
for(Student s:ss) {
System.out.println(s.getName()+"--"+s.getAge());
}
}
}
自定义学生类
public class Student implements Comparable<Student>{
private String name;
private int age;
public Student() {
super();
}
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public int compareTo(Student s) {
//年龄从小到大
//this 表示当前的
//s.可以当成传入的
//两个年龄的差值
//后面比前面大
//就是从小到大
//this是对象 s是参数
//如果按字典顺序此 String 对象位于参数字符串之前,则比较结果为一个负整数。
//如果按字典顺序此 String 对象位于参数字符串之后,则比较结果为一个正整数。 //如果这两个字符串相等,则结果为 0
int num = this.age -s.age ;
//年龄一样 比较名字
int num2 = (num==0)?(this.name.compareTo(s.name)) :num ;
return num2;
}
张国荣--5
张杰--6
李--7
樱木花道--8
迈克尔杰克逊--8
}
年龄按从小到大排序
年龄一样比较名字
这里需要我们自己分析主要条件 次要条件
主要是重写这个Comparable方法
public class Student implements Comparable<Student>{
private String name ;
private int age ;
public Student() {
super();
// TODO Auto-generated constructor stub
}
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
@Override
public int compareTo(Student s) {
//主要条件:按照姓名的长度从小到大排序
int num = this.name.length() - s.name.length() ;
//次要条件:姓名长度一样,姓名内容不一定相同
int num2 = (num==0)?(this.name.compareTo(s.name)):num ;
//如果姓名长度一样,姓名内容也一样,年龄可能不同
int num3 = (num2==0)?(this.age-s.age):num2;
return num3;
}
}
这里就写出了三个条件
有时给出了主要 次要自己写
TreeSet中构造器排序 ------Comparator
方式(1)和自然排序一样
方式(2)匿名内部类-------在内部类中重写方法
import java.util.TreeSet;
//构造器排序
//使用比较器排序
//主要条件按姓名的长度从小到大排序
方式(1)
首先给一个学生类
public class Student{
private String name ;
private int age ;
public Student() {
super();
// TODO Auto-generated constructor stub
}
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
}
测试类
public class TreeSetDemo3 {
public static void main(String[] args) {
//创建一个TreeSet集合对象,有参构造方式
TreeSet<Student> tt=new TreeSet<Student> (new MyComparator));
//创建学生对象
Student s1 = new Student("zhangguorong", 20) ;
Student s2 = new Student("wanglihong", 20) ;
Student s3 = new Student("wenzhang", 20) ;
Student s4 = new Student("zhangguorong", 28) ;
Student s5 = new Student("gaoyuanyuan", 25) ;
Student s6 = new Student("zhaoyouting", 29) ;
Student s7 = new Student("zhaoyouting", 35) ;
Student s8 = new Student("liushishi", 34) ;
Student s9 = new Student("wuqilong", 43) ;
Student s10 = new Student("wenzhang", 27) ;
//添加集合中
tt.add(s1) ;
tt.add(s2) ;
tt.add(s3) ;
tt.add(s4) ;
tt.add(s5) ;
tt.add(s6) ;
tt.add(s7) ;
tt.add(s8) ;
tt.add(s9) ;
tt.add(s10) ;
for (Student s:tt) {
System.out.println(s.getName()+"------"+s.getAge());
}
}
wenzhang------27
wuqilong------43
liushishi------34
wanglihong------20
gaoyuanyuan------25
zhaoyouting------29
zhaoyouting------35
zhangguorong------20
zhangguorong------28
}
定义子实现类比较器接口
import java.util.Comparator;
public class MyComparator implements Comparator<Student>{
@Override
public int compare(Student s1, Student s2) {
s1----自然排序的this---对象
s2-----自然排序的S------参数
//主要条件:按姓名的长度从小到大
int num=s1.getName().length()-s2.getName().length();
//次要条件:姓名长度一样,比较内容
int num2=(num==0)?(s1.getName().compareTo(s2.getName())):num;
//内容一样,不一定年龄不一样
int num3=(num==0)?(s1.getAge()-s2.getAge()):num2;
return num3;
}
}
这要写一个比较器接口
方法二就比较简便
使用匿名内部类(推荐使用)
import java.util.Comparator;
import java.util.TreeSet;
public class TreeSetDemo4 {
public static void main(String[] args) {
// TODO Auto-generated method stub
//创建一个TreeSet集合对象
TreeSet<Student> tt=new TreeSet<Student> (new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
// TODO Auto-generated method stub
//s1----->刚才使用自然排序里面 this
//s2----->刚才使用自然排序里面的s
//主要条件:按姓名的长度从小到大排序
int num=s1.getName().length()-s2.getName().length();
//次要条件 姓名长度一样 内容不一定一样
int num2=(num==0)?(s1.getName().compareTo(s2.getName())):num;
//内容一样,不一定年龄一样
int num3 = (num2==0)?(s1.getAge()-s2.getAge()):num2 ;
return num3;
}
});
//创建学生对象
Student s1 = new Student("zhangguorong", 20) ;
Student s2 = new Student("wanglihong", 20) ;
Student s3 = new Student("wenzhang", 20) ;
Student s4 = new Student("zhangguorong", 28) ;
Student s5 = new Student("gaoyuanyuan", 25) ;
Student s6 = new Student("zhaoyouting", 29) ;
Student s7 = new Student("zhaoyouting", 35) ;
Student s8 = new Student("liushishi", 34) ;
Student s9 = new Student("wuqilong", 43) ;
Student s10 = new Student("wenzhang", 27) ;
//添加集合中
tt.add(s1) ;
tt.add(s2) ;
tt.add(s4) ;
tt.add(s5) ;
tt.add(s6) ;
tt.add(s7) ;
tt.add(s8) ;
tt.add(s9) ;
tt.add(s10) ;
for (Student s:tt) {
System.out.println(s.getName()+"------"+s.getAge());
}
wenzhang------27
wuqilong------43
liushishi------34
wanglihong------20
gaoyuanyuan------25
zhaoyouting------29
zhaoyouting------35
zhangguorong------20
zhangguorong------28
}
}
总结
comparable
在子实现类中重写方法
继承Comparable接口 comparable不用写
子实现类重写方法
Comparator
(1)
自定义类不做任何操作
写一个comparator接口 接口中重写方法
测试类中实现接口
(2)
匿名内部类
(推荐使用)