Java中接口Set的特点及方法说明

网友投稿 388 2022-08-28


Java中接口Set的特点及方法说明

目录接口Set的特点及方法Set接口及其实现类Set接口有两个实现类Set接口:Set存储元素是无序不可以重复的因为Set接口也是Collection的子接口1、TreeSet:树状集合、存放有序2、HashSet:散列集合、高效快速

接口Set的特点及方法

1、特点:无序,不可重复;

2、实现类:添加的方法:

add(Object obj);addAll(Collection c);

Set中没有修改的方法,可以间接修改,先删除再添加;

删除的方法:

remove(Object obj);removeAll(Collection c);retainAll(Collection c)仅保留set中那些包含在指定的Collection中的元素;clear()清除所有元素;

查询的方法:

contains(Object obj)查询set中是否包含指定元素,包含返回true;containsAll(Collection c)查询set中是否包含指定的多个元素,全部包含返回true;isEmpty()判断set是否为空,为空返回true;

3、set集合的遍历:使用for循环;

使用iterator迭代器:it.hasNext()如果有下一个元素,返回true;

it.next()返回下一个元素;it.remove()删除迭代器返回的最后一个元素;

Set接口及其实现类

Set接口有两个实现类

散列集合:HashSet(Hash算法)树集合:TreeSet(二叉树算法)

Set接口:Set存储元素是无序不可以重复的

HashSet:元素是否重复是依据:元素自身equals比较进行判定的。TreeSet:元素是否重复是依据:CompareTo方法返回是否为0。

因为Set接口也是Collection的子接口

所以也可以使用Collection实现的所有方法,其中常用的有:

添加:add()删除:remove()检查元素是否存在:contains(Object o)迭代器:iterator()

1、TreeSet:树状集合、存放有序

语法:Set set = new TreeSet();

说明:TreeSet添加元素时,首先按照compareTo()进行比较,而TreeSet要想指定集合的存放顺序,被排序的对象需实现Comparable接口,这个接口强行的对每个实现类对象进行整体的排序,这种排序称为类的自然排序,这个接口有个抽象方法compareTo,该方法称为自然排序的方法。

向TreeSet中添加的元素必须是同一个类的。(否则底层调用compareTo时会报类型转换异常)

public class Person implements Comparable{

int id;

int age;

String name;

public Person(int id,int age,String name){

super();

this.id = id;

this.age = age;

this.name = name;

}

public String toString(){

return "Person [id = " + id + ", age = " + age + ", name = " +http:// name + "]";

}

@Override

public int compareTo(Object o){//按照id排序

Person p;

if(o instanceof Pserson){

p = (Person)o;

}else{

return -1;//-1代表传入的参数比我本身要小

}

int diff = this.id - p.id;

if(diff!=0){

diff = diff / Math.abs(diff);//差值除以本身绝对值,可以得到+1或-1的值。

}

return diff;

}

该compareTo方法是根据对象的id进行比较,也可以根据自己的需求自定义比较内容:

this.id 是当前对象的ido.id 是指定对象的id(也就是传入对象的id)

调用sort方法时可以自定义升序或降序:

升序:this.id - o.id(this.id < o.id 结果为负、this.id > o.id 结果为正,this.id = o.id 结果为0)降序:o.id - this.id(thhttp://is.id < o.id 结果为正、this.id < o.id 结果为负,this.id = o.idnPIjApqHsS 结果为0)

上述代码中,我们使用的是this.id - o.id,所以我们是升序排序的(默认情况就是升序排序的)。

import java.util.Set;

import java.util.TreeSet;

public class Demo{

public static void main(String[] args){

Set set = new TreeSet();

Person p1 = new Person(1,18,"小明");

Person p2 = new Person(2,5,"小强");

Person p3 = new Person(3,20,"小张");

set.add(p1);

set.add(p2);

set.add(p3);

set.add(p3);//重复的元素不会被添加到集合中

System.out.println(set.size());

Iterator it = set.iterator();

while(it.hasNext()){

System.out.println(it.next());

}

}

}

compareTo方法就是为了实现Comparable接口而存在的,而实现Comparable接口就是为了可以直接使用sort()方法对该对象进行自定义排序。

注意:TreeSet是不能存在null元素(HashSet是可以存储null值的),向TreeSet中添加元素时,首先按照compareTo()进行比较,元素底层调用compareTo方法时会报空指针异常。

2、HashSet:散列集合、高效快速

语法:Set set = new HashSet();

说明:HashSet存储的对象,应该重写hashCode()和equals()两个方法,在添加元素的时候会根据我们重写hashCode()方法计算元素的hash值,根据哈希值计算元素存储的位置(哈希地址),如果该哈希地址没有元素则会直接添加成功,如果该位置有其他元素会根据equals方法判断是否为同一个对象,如果结果返回true则不会添加,如果为false则会以链表的形式追加到该哈希地址处。(底层根据HashMap实现)

在不指定泛型的情况下可以为不同的类型的值;

public class Person{

int id;

String name;

public Person(int id, String name) {

super();

this.id = id;

this.name = name;

}

//重写hashCode方法只根据id进行计算hash值

@Override

public int hashCode() {

final int prime = 31;

int result = 1;

result = prime * result + id;

return result;

}

//重写equals方法

@Override

public boolean equals(Object obj) {

if (this == obj)

return true;

if (obj == null)

return false;

if (getClass() != obj.getClass())

return false;

Person other = (Person) obj;

if (id != other.id)

return false;

return true;

}

//重写toString方法,方便在我们输出的时候查看

@Override

public String toString() {

return "Person [id=" + id + ", name=" + name + "]";

}

}

public class Demo{

public static void main(String[] args){

Set set = new HashSet();

Person p1 = new Person(1,"小明");

Person p2 = new Person(2,"小张");

Person p3 = new Person(3,"小李");

set.add(p1);

set.add(p2);

set.add(p3);

//在我们添加成功以后修改其决定hash值的id

p2.id = 5;

//在删除时会导致删除不掉(如果修改的是name则不会出现删除不掉的效果)

//因为之前的元素存储在id为2计算的哈希地址的位置,现在是去id为5计算的哈希地址出去删除,所以删除不掉

//set.remove(p2);

//会添加到id为5计算的哈希地址,所以会添加成功(虽然属性相同,但是之前的是存储在根据id为2计算的哈希地址位置)

set.add(p2);

//当我们继续添加的时候,equals返回的是true,所以不会添加成功

set.add(p2);

//此时创建一个id为2的对象继续添加

Person p4 = new Person(2,"小张");

set.add(p4);//会添加id为2计算的哈希地址位置,虽然该位置有元素,但是之前的元素已经被修改了,所以会添加成功

System.out.println("集合的长度为:"+set.size());

Iterator it = set.iterator();

while(it.hasNext()){

System.out.println(it.next());

}

}

}

输出结果:

集合的长度:5Person [id=1, name=小明]        //根据id为1计算的哈希地址Person [id=5, name=小张]        //根据id为2计算的哈希地址(原p2对象以id为2的哈希地址进行存储,但是后来id被修改为5了)Person [id=2, name=小张]        //根据id为2计算的哈希地址(p4对象)Person [id=3, name=小李]        //根据id为3计算的哈希地址Person [id=5, name=小张]        //根据id为5计算的哈希地址(修改以后的p2以id为5计算的哈希地址存储)

HashSet存储元素的存储过程:

首先说一下HashSet存储对象的方式:首先根据我们重写的HashCode方法计算出Hash值,根据Hash值来判断存入Set中的元素是否重复和存储在Set集合中的哈希地址,如果该Hash地址为空,则会直接将该对象存储到该哈希地址,如果该哈希地址有元素,会根据equals方法判断是否为同一个对象,如果结果返回true,说明两个对象是同一对象,则不会添加该对象,如果返回的是false,说明元素本身是不同的,则会以链表的形式同时存储到该哈希地址的位置。

总结:说一下上面的执行过程,Set集合是根据我们重写的HashCode方法中的属性,来计算Hash值,来判断存入Set中的元素是否重复和存储在Set集合中哈希地址,当我们在存储之后再进行修改决定计算Hash值的属性时,会导致程序出现意想不到的结果,我们首先根据id为2计算出了一个存储该对象的哈希地址,当我们修改了id为5后,再进行删除操作时,它会根据id为5计算一个Hash值,去该Hash值对应的哈希地址去删除元素,因为我们之前存储的哈希地址是根据id为2计算出来的,所以会导致本应删除的元素删除不掉,而当我们再进行add的时候,我们根据id为5的Hash值去存储时发现,id为5的地址并没有元素,所以存储成功,虽然和之前id为2时计算Hash值存储位置的元素属性值一样,但是还是会存储成功的,然而,当我们再创建一个id为2的对象进行存储时,虽然哈希地址相同,但此时之前根据该哈希地址的对象已经改变了(id修改为5了),所以会将新创建的id为2的对象以链表的形式同时存储在该哈希地址的位置,所以当我们操作HashSet集合时,不要去修改决定计算Hash值的元素属性。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Pytest之美化插件进度条pytest-sugar(pytest常用插件)
下一篇:pytest之pytest-timeout插件之设置超时时间【用例执行时间与设置的超时时间比较】 || 超时退出执行测试用例
相关文章

 发表评论

暂时没有评论,来抢沙发吧~