1、集合框架Set(HashSet哈希表存储、重复元素存储底层探究)
HashSet 具有父类Se t接口的特性,底层数据结构是哈希表
(一).HashSet哈希表存储
一、元素是无序(存入和取出的顺序不一定一致)
package com.qukang.set;
import java.util.HashSet;
public class SetDemo {
public static void main(String[] args) {
HashSet hs=new HashSet<>();
hs.add("zs");
hs.add("ls");
hs.add("ww");
hs.add("mazi");
for (Object obj : hs) {
System.out.println(obj);
}
}
}
- 输出结果
- 并且元素不可以重复;
package com.qukang.set;
import java.util.HashSet;
public class SetDemo {
public static void main(String[] args) {
HashSet hs=new HashSet<>();
hs.add("zs");
hs.add("ls");
hs.add("ww");
hs.add("mazi");
hs.add("zs");
for (Object obj : hs) {
System.out.println(obj);
}
System.out.println(hs.size());
}
}
- 输出结果
(二).重复元素存储底层探究
特点:HashSet 把内存当成了一张表,把空间分成了N份,每次先比较HashCode值,HashCode值就相当于这个张表的ID,如果HashCode值返回的是true,就确定了这个对象摆放的位置,就调用equals方法来比较元素,相比于Arraylist HashSet比Arraylist 多调用了HashCode方法。
一、 HashSet元素是不可重复的,针对于基本数据类型以及String,引用数据类型去重需要重写hashCode方法以及equals反法
a .返回HashCode值一样时每次都要调用equals方法
package com.qukang.set;
import java.util.HashSet;
public class SetDemo {
public static void main(String[] args) {
HashSet hs=new HashSet<>();
hs.add(new Person("zs",12));
hs.add(new Person("ls",13));
hs.add(new Person("ww",14));
hs.add(new Person("mz",15));
hs.add(new Person("zs",12));
System.out.println("去重之后的长度:"+hs.size());
}
}
class Person{
private String uname;
private int age;
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Person(String uname, int age) {
super();
this.uname = uname;
this.age = age;
}
public Person() {
super();
}
@Override
public String toString() {
return "Person [uname=" + uname + ", age=" + age + "]";
}
@Override
public int hashCode() {
// TODO Auto-generated method stub
System.out.println("来了老弟......"+this.getUname());
return 60;
}
@Override
public boolean equals(Object obj) {
// TODO Auto-generated method stub
if(obj instanceof Person) {
Person p=(Person)obj;
System.out.println(this.getUname()+"----equals-----"+p.getUname());
return this.getUname().equals(p.getUname()) && this.getAge()==p.getAge();
}
return false;
}
}
a .返回HashCode值一样时输出结果
b .返回HashCode值不一样时,只有找到HashCode值一样的时候才调用equlas方法
package com.qukang.set;
import java.util.HashSet;
public class SetDemo {
public static void main(String[] args) {
HashSet hs=new HashSet<>();
hs.add(new Person("zs",12));
hs.add(new Person("ls",13));
hs.add(new Person("ww",14));
hs.add(new Person("mz",15));
hs.add(new Person("zs",12));
System.out.println("去重之后的长度:"+hs.size());
}
}
class Person{
private String uname;
private int age;
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Person(String uname, int age) {
super();
this.uname = uname;
this.age = age;
}
public Person() {
super();
}
@Override
public String toString() {
return "Person [uname=" + uname + ", age=" + age + "]";
}
@Override
public int hashCode() {
// TODO Auto-generated method stub
System.out.println("来了老弟......"+this.getUname());
return this.getUname().hashCode() + this.age;
}
@Override
public boolean equals(Object obj) {
// TODO Auto-generated method stub
if(obj instanceof Person) {
Person p=(Person)obj;
System.out.println(this.getUname()+"----equals-----"+p.getUname());
return this.getUname().equals(p.getUname()) && this.getAge()==p.getAge();
}
return false;
}
}
b .返回HashCode值不一样时只有找到HashCode值一样的时候才调用equlas反法的结果
2、集合框架TreeSet(自然排序、数据结构二叉树、比较器排序)
- TreeSet自然排序
- TreeSet可以对set集合中元素进行排序
- String实现了Comparable接口,所以可以直接进行排序
- 引用数据类型想要排序,必须实现Comparable接口
- 其他引用数据类型没有实现Comparable接口,那么会出现java.lang.ClassCastException: com.javaxl.Peroon cannot be cast to java.lang.Comparable,实现引用数据类型实现此接口就没问
1.排序注意:
- 返回的共享数据是无序的,需要自己进行排序
- 因为String实现了Comparable接口,所以可以直接进行排序
- 但是引用数据类型想要排序,必须实现Comparable接口
- 注意:排序时,当主要条件相同时,一定要判断次要条件
*/
a.TreeSet String类型排序
package com.qukang.set;
import java.util.Iterator;
import java.util.TreeSet;
public class TreeSetDome {
public static void main(String[] args) {
TreeSet ts=new TreeSet<>();
ts.add("zs");
ts.add("ls");
ts.add("ww");
ts.add("mz");
ts.add("ed");
Iterator it = ts.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}
TreeSet String 类型排序结果:
b.TreeSet 引用累计进行排序有两种方法
- 1.实现Comparable接口,让元素具有比较性
缺点:维护性较差,就也是程序的拓展性较差;
package com.qukang.set;
import java.util.Iterator;
import java.util.TreeSet;
public class TreeSetDome {
public static void main(String[] args) {
TreeSet ts=new TreeSet<>();
ts.add(new Person("zs",12));
ts.add(new Person("ls",13));
ts.add(new Person("ww",14));
ts.add(new Person("mz",12));
Iterator it = ts.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}
class Person implements Comparable<Person>{
private String uname;
private int age;
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Person(String uname, int age) {
super();
this.uname = uname;
this.age = age;
}
public Person() {
super();
}
@Override
public String toString() {
return "Person [uname=" + uname + ", age=" + age + "]";
}
@Override
public int hashCode() {
// TODO Auto-generated method stub
System.out.println("来了老弟......"+this.getUname());
return this.getUname().hashCode() + this.age;
}
@Override
public boolean equals(Object obj) {
// TODO Auto-generated method stub
if(obj instanceof Person) {
Person p=(Person)obj;
System.out.println(this.getUname()+"----equals-----"+p.getUname());
return this.getUname().equals(p.getUname()) && this.getAge()==p.getAge();
}
return false;
}
@Override
public int compareTo(Person o) {
// TODO Auto-generated method stub
int num=this.getAge() - o.getAge();
if(num==0) {
return this.getUname().compareTo(o.getUname());
}
return num;
}
}
CompareTo方法:
- 本方法用来定义排序的规则
- 正数:代表后面的比前面的大
- 0:代表后面和前面一样
- 负数:代表后面的比前面的小
- this.:代表还没有存放在容器中的对象
- o:代表已经在容器的对象
注意:排序时,当主要条件相同时,一定要判断次要条件
@Override
public int compareTo(Person o) {
// TODO Auto-generated method stub
int num=this.getAge() - o.getAge();
if(num==0) {
return this.getUname().compareTo(o.getUname());
}
return num;
}
- 实现Comparable接口结果:
- 2.实现Comparator接口,让容器具有比较性
针对于需求而发生改变
package com.qukang.set;
import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;
public class TreeSetDome {
public static void main(String[] args) {
TreeSet ts=new TreeSet<>(new PersonComp());
ts.add(new Person("zs",12));
ts.add(new Person("ls",13));
ts.add(new Person("ww",14));
ts.add(new Person("mz",12));
Iterator it = ts.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}
class PersonComp implements Comparator<Person>{
/**
* 本方法用来定义排序的规则
* 正数:代表后面的比前面的大
* 0:代表后面和前面一样
* 负数:代表后面的比前面的小
* o1:代表还没有存放在容器中的对象
* o2:代表已经在容器的对象
*/
@Override
public int compare(Person o1, Person o2) {
// TODO Auto-generated method stub
int num1=o1.getUname().compareTo(o2.getUname());
if(num1==0) {
return o2.getAge()-o1.getAge();
}
return num1;
}
}
Comparator方法:
相对于ComparaTo方法Comparator
- 本方法用来定义排序的规则
- 正数:代表后面的比前面的大
- 0:代表后面和前面一样
- 负数:代表后面的比前面的小
- o1:代表还没有存放在容器中的对象
- o2:代表已经在容器的对象
- 注意:排序时,当主要条件相同时,一定要判断次要条件
@Override
public int compare(Person o1, Person o2) {
// TODO Auto-generated method stub
int num1=o1.getUname().compareTo(o2.getUname());
if(num1==0) {
return o2.getAge()-o1.getAge();
}
return num1;
}
实现Comparator接口结果:
两个接口的区别
当两种排序都存在时,比较器排序优先级更高
因此比较器用的多一些,在实际开发中,很多时候,引用数据类型是否具有比较性,或者比较规则,可能不由开发人员自己决 定,
那么开发人员想要对应的引用数据类型按照自己的排序方式进行排列,那么就需要实现comparator接口,实现compare方法
3、泛型
泛型的好处:
a.将运行的时的错误转换到编译时错误
b.提升了代码的健壮性,简化了代码
-
运行时报错:
-
编译时报错:
-
如果你不写泛型,就需要写一下代码来代替;
package com.qukang.set;
import java.util.HashSet;
import java.util.Iterator;
public class HashSetDemo {
public static void main(String[] args) {
HashSet hs=new HashSet<>();
hs.add(22);
hs.add(32);
hs.add(34);
hs.add(454);
hs.add(88);
hs.add("zs");
Iterator it = hs.iterator();
while(it.hasNext()) {
Object obj=it.next();
if(obj instanceof Integer) {
int i=(Integer)obj;
if(i==0) {
System.out.println(i);
}
}
}
}