4、Set接口(Set集合的功能和Collection是一致的。)
Set:元素是无序(存入和取出的顺序不一定一致),元素不可以重复。
——HashSet:底层数据结构是哈希表。是线程不安全的。不同步。
HashSet是如何保证元素唯一性的呢?
是通过元素的两个方法,hashCode和equals来完成。
如果元素的HashCode值相同,才会判断equals是否为true。
如果元素的hashcode值不同,不会调用equals。
注意,对于判断元素是否存在,以及删除等操作,依赖的方法是元素的hashcode和equals方法。
——TreeSet:
有序的存放:TreeSet 线程不安全,可以对Set集合中的元素进行排序,底层数据结构是二叉树。
保证元素唯一性的依据:
compareTo方法return 0.
TreeSet排序的第一种方式:让元素自身具备比较性。
元素需要实现Comparable接口,覆盖compareTo方法。
也种方式也成为元素的自然顺序,或者叫做默认顺序。
TreeSet的第二种排序方式。
当元素自身不具备比较性时,或者具备的比较性不是所需要的。
这时就需要让集合自身具备比较性。 在集合初始化时,就有了比较方式。
定义了比较器,将比较器对象作为参数传递给TreeSet集合的构造函数。自定义比较器,优先于让元素自身具备比较性
定义一个类,实现Comparator接口,覆盖compare方法。
TreeSet(Comparator<? super E> comparator) 构造一个新的空 TreeSet,它根据指定比较器进行排序。
HashSet示例代码
import java.util.HashSet;
import java.util.Iterator;
public class HashSetDemo {
public static void main(String[] args) {
HashSet hs = new HashSet();
hs.add("java01");
hs.add("java02");
hs.add("java03");
System.out.println(hs.add("java03")); // false,HashCode 值存在
System.out.println(hs.contains("java03")); // true
Iterator it = hs.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
}
}
/*
往hashSet集合中存入自定对象
姓名和年龄相同为同一个人,重复元素。
*/
public class HashSetTest {
public static void main(String[] args) {
HashSet hs = new HashSet();
hs.add(new Person("lisi01",20));
hs.add(new Person("lisi02",21));
hs.add(new Person("lisi02",21));
hs.add(new Person("lisi04",23));
// 首先
System.out.println(hs.contains(new Person("lisi01",20))); // false
for (Iterator it = hs.iterator();it.hasNext();){
System.out.println(it.next());
/* Person{name='lisi02', age=21}
Person{name='lisi04', age=23}
Person{name='lisi01', age=20}
Person{name='lisi02', age=21}*/
// 造成重复的原因:
// 添加对象时,会在该集合的哈希表中判断有没有这个哈希值,如果存在,会调用equals()【比较的是地址】判断是否相等
// 如果该对象的hashcode不存在,添加,不会调用equals。
// 所以需要重写hashcode 和 equals 方法
}
}
}
class Person{
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public int hashCode() {
System.out.println(this.name.hashCode()+"...hashcode");
return name.hashCode()+age*19;
}
public boolean equals(Object o) {
if(!(o instanceof Person)){
return false;
}
Person p = (Person)o;
System.out.println(this.name+".equals"+p.name);
return this.name.equals(p.name) && this.age == p.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 "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
TreeSet 示例代码
import java.util.Iterator;
import java.util.TreeSet;
// TreeSet 可对对象进行排序
public class TreeSetDemo {
public static void main(String[] args) {
TreeSet ts = new TreeSet();
ts.add("java2");
ts.add("java1");
ts.add("java0");
ts.add("java5");
System.out.println(ts.add("java5")); // false 会在comparTo() 方法中进行比较,返回0 已经存在,不添加
for(Iterator it = ts.iterator();it.hasNext();){
System.out.println(it.next());
}
/*java0
java1
java2
java5*/
}
}
import java.util.Iterator;
import java.util.TreeSet;
/*
需求:
往TreeSet集合中存储自定义对象学生。
想按照学生的年龄进行排序。
* */
/*
当元素不具备比较性时,会抛出 // ClassCastException: 集合.Student cannot be cast to java.lang.Comparable
TreeSet排序的第一种方式:让元素自身具备比较性。
元素需要实现Comparable接口,覆盖compareTo方法。
也种方式也成为元素的自然顺序,或者叫做默认顺序。
*/
public class TreeSetDemo2 {
public static void main(String[] args) {
TreeSet ts = new TreeSet();
ts.add(new Student("xiaoming1",20));
ts.add(new Student("xiaoming2",21)); // ClassCastException: 集合.Student cannot be cast to java.lang.Comparable
ts.add(new Student("xiaoming3",19));
ts.add(new Student("xiaoming4",19));
for(Iterator it = ts.iterator();it.hasNext();){
System.out.println(it.next());
}
/*Student{name='xiaoming3', age=19}
Student{name='xiaoming4', age=19}
Student{name='xiaoming1', age=20}
Student{name='xiaoming2', age=21}*/
}
}
class Student implements Comparable {
private String name;
private int age;
public Student(String name, int age) {
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(Object o) {
if(!(o instanceof Student)){
throw new RuntimeException("不是学生类");
}
Student s = (Student) o;
if(this.age > s.age){
return 1;
}
if(this.age == s.age){
// 如果年龄相等,对姓名进行比计较,String 类已经实现了compareTo()
return this.name.compareTo(s.name);
}
return -1;
// 按照输入的顺序输出,只需要return 1 即可
// 按照输入的顺序逆序输出,只需要return -1 即可
}
}
实现原理
比较:返回-1放左边,返回1放右边,0进行其他项比较
TreeSet 第二种比较方式,让容器自身具备比较器(更实用)
package 集合;
/*
当元素自身不具备比较性,或者具备的比较性不是所需要的。
这时需要让容器自身具备比较性。
定义了比较器,将比较器对象作为参数传递给TreeSet集合的构造函数。
当两种排序都存在时,以比较器为主。
定义一个类,实现Comparator接口,覆盖compare方法。
*/
import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;
public class TreeSetDemo3 {
public static void main(String[] args) {
TreeSet ts = new TreeSet(new MyCompare()); // 传入自己的构造器
ts.add(new Student("xiaoming1",20));
ts.add(new Student("xiaoming4",21));
ts.add(new Student("xiaoming3",19));
ts.add(new Student("xiaoming33",19));
ts.add(new Student("xiaoming4",19));
for(Iterator it = ts.iterator();it.hasNext();){
System.out.println(it.next());
}
}
}
// 创建一个自定义的比较器,通过年龄进行排序
class MyCompare implements Comparator {
@Override
public int compare(Object o1, Object o2) {
Student s1 = (Student) o1;
Student s2 = (Student) o2;
int num = s1.getName().compareTo(s2.getName());
if(num==0){
// 对年龄进行比较 Integer 实现了compareTo()
Integer s11= s1.getAge();
Integer s22= s2.getAge();
return s11.compareTo(s22);
}
return num;
}
}
class Student implements Comparable {
private String name;
private int age;
public Student(String name, int age) {
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(Object o) {
if(!(o instanceof Student)){
throw new RuntimeException("不是学生类");
}
Student s = (Student) o;
if(this.age > s.age){
return 1;
}
if(this.age == s.age){
// 如果年龄相等,对姓名进行比计较,String 类已经实现了compareTo()
return this.name.compareTo(s.name);
}
return -1;
// 按照输入的顺序输出,只需要return 1 即可
// 按照输入的顺序逆序输出,只需要return -1 即可
}
}
TreeSet 练习:
package 集合;
import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;
/*
* 按照字符串长度进行排序
* 字符串本身具备比较性,但它的比较方式不是我们需要的
* 这时就需要自定义比较器
* */
public class TreeSet练习 {
public static void main(String[] args) {
TreeSet ts = new TreeSet(new StringLengthCompare());
ts.add("aaaa");
ts.add("b");
ts.add("bbb");
ts.add("ccc");
ts.add("aa");
for (Iterator it = ts.iterator(); it.hasNext();){
System.out.println(it.next());
}
}
}
// 自定义比较器
class StringLengthCompare implements Comparator{
@Override
public int compare(Object o1, Object o2) {
String s1 = (String)o1;
String s2 = (String)o2;
Integer s11 = s1.length();
Integer s22 = s2.length();
int num = s11.compareTo(s22);
if(num == 0){
return s1.compareTo(s2);
}
return num;
}
}