重点
1.Set接口的特点讲解
Set:接口
1.一个不包含重复元素的 collection。
2.最多包含一个 null 元素
3.一般使用它实现类:HashSet,LinkedHashSet,TreeSet
4.Set集合存和取的顺序不一样,【每一次取的顺序都可能不一样】
List:接口
1.List是可存储相同元素
2.List存的取的元素顺序是一样
2.HashSet
1.此类实现 Set 接口
2.由哈希表(实际上是一个 HashMap 实例)支持。
3.它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。
4.此类允许使用 null 元素。
Set遍历一、增强for循环
Set遍历二、迭代器
3.hashCode与equals的原理
1 .通过set集合的add方法添加元素时,内部会调用hashcode和equals方法
2. 如果比较的hashcode的值是一样的话,会调用equals方法,equals方法返回true,就不存元素,返回false就存元素
3. 如果比较的hashcode的值不一样,就直接存元素
4.hashCode与equals的优化
- 优化:
Person
-name
-age - 1.如果名字不一样,就不需要调用equals方法,从而优化代码
- return this.name.hashCode()
- 2.hashCode(): 属性相同的对象返回值必须相同, 属性不同的返回值尽量不同(提高效率)
return this.name.hashCode() + this.age;
5.LinkedHashSet
LinkedHashSet是HashSet的子类
LinkedHashSet 存和取的顺序是一样
6.TreeSet
TreeSet是一种能排序集合
默认情况下,TreeSet存Integer时,由小到大排序
默认情况下,TreeSet存String时,字母的由小到大排序
Integer和String这两个类都内部实现了comparable接口
7.TreeSet保存自定义对象
自定义对象必须实现comparable接口?
实现这个接口的目的是告诉TreeSet你的元素的排序规则
实现了comparable接口的类,要实现compareTo方法
compareTo方法:
0-只存一个元素,第一个元素
-1:存的顺序倒序
1:存的顺序正序
8.TreeSet排序的原理
TreeSet是使用二叉权存数据
0:不存
负数:存在左边
正数:存在右边
练习题
1.HashSet存储自定义对象保证元素唯一性
//思路:需要重写hashCode()和equals()方法
public int hashCode() {
// TODO Auto-generated method stub
System.out.println(this.name + ":" + this.name.hashCode());
*//**
* 优化:
* 1.如果名字不一样,就不需要调用equals方法,从而优化代码
* return this.name.hashCode()
* 2.hashCode(): 属性相同的对象返回值必须相同, 属性不同的返回值尽量不同(提高效率)
*//*
return this.name.hashCode() + this.age;
}
@Override
public boolean equals(Object obj) {
// TODO Auto-generated method stub
Person other = (Person) obj;
System.out.println(this.name + "....比较...." + other.name);
return this.age == other.age && this.name.equals(other.name);
- 熟悉原理后,可用快捷键自动生成。
2.产生10个1-20之间的随机数要求随机数不能重复
- 关键:HashSet,Random,While(true)
public static void main(String[] args) {
//思路:生成0-20的随机数,判断不为0才添加,判断集合大小为10才退出循环
Random random = new Random();
Set<Integer> set = new HashSet<Integer>();
while(true){
int i = random.nextInt(21);//0~20
if (i!=0) {
set.add(i);
}
if (set.size()==10) {
break;
}
}
for(Integer ig : set){
System.out.println(ig);
}
}
3.从键盘读取一行输入,去除重复的字符
public static void main(String[] args) {
System.out.println("请输入字符串:");
Scanner scanner = new Scanner(System.in);
String str = scanner.next();
System.out.println(str);
Set<Character> cha = new HashSet<Character>();
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
//System.out.println(c);
cha.add(c);
}
System.out.println(cha);
for(Character ch : cha){
System.out.println(ch);
}
}
4.//将List集合中的重复元素去掉(set实现)
//思路:遍历List集合的每一个元素将它添加到Set集合中,Set然后会自动排除重复的元素(字符串)
public static void main(String[] args) {
//将List集合中的重复元素去掉(set实现)
List<Integer> list = new ArrayList<Integer>();
list.add(12);
list.add(15);
list.add(16);
list.add(16);
System.out.println("list:"+list);
Set<Integer> set = new HashSet<Integer>();
for(Integer i : list){
set.add(i);
}
System.out.println("set:"+set);
}
5.Person 要按年龄和名字进行排序
@Override
public int compareTo(Person other) {
// TODO Auto-generated method stub
//1.按年龄的由小到大排序
int num = this.age - other.age;
System.out.println(this.name + "..比较..." + other.name + " 年龄差:" + num);
//if(num == 0) num = 1;
//2.如果年龄一样,根据名字排序 [字符串一样,比较的结果也是0]
//String s;
if(num == 0){
num = this.name.compareTo(other.name);
}
return num;
}
6. Student 要按名字的长度,名字和年龄进行排序
public class Demo04 {
public static void main(String[] args) {
//TreeSet存储自定义对象并遍历,按照姓名长度、字母、年龄排序
Set<Student> students = new TreeSet<Student>();
students.add(new Student("asd", 12));
students.add(new Student("cbdh", 22));
students.add(new Student("csdf", 32));
students.add(new Student("asd", 12));
System.out.println(students);
for(Student stu : students){
System.out.println(stu);
}
}
}
class Student implements Comparable<Student>{
private String name;
private int age;
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
@Override
public int compareTo(Student other) {
// TODO Auto-generated method stub
//1.按照姓名长度
int i = this.name.length() - other.name.length();
//2.字母排序
if(i==0){
i = this.name.compareTo(other.name);
}
//3.年龄排序
if (i==0) {
i= this.age - other.age;
}
return i;
}
}
面试题
1.你在开发中经常使用Java的哪些包?
1.java.util包,这个包有很集合框架:List/Set/Map
…
2.为什么自动生成hashcode的时有个31的数
①31是一个质数,质数是能被1和自己本身整除的数,没有公约数
②3l这个数既不大也不小,
■大的话可能超过int的取值范围
■小的话,相同机率出现比较多
③31这个数好算,2的五次方-1,1向左移动5位 1<<5
总结
通过对集合Set接口的3个实现类HashSet、LinkedHashSet 、TreeSet的学习,知道了Set集合的很多细节的地方,比如Set集合不能存重复的元素,存和取的顺序也不同,对于自定义对象想要保证元素的唯一性,需要自己重写hashCode和equals方法,当了解到了他们的实现原理时,可以对他们调优。实际开发中,可以利用快捷键自动生成自定义对象的hashCode和equals方法。然后就是LinkedHashSet,它是HashSet的子类,特点时存和取的顺序是一样。而TreeSet是一种能排序集合,内部实现了comparable接口。使用自定义对象时,要实现comparable接口,重写compareTo()方法。坚持敲代码!