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<E> set = new TreeSet<E>();

说明: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 = " + 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 是当前对象的id
  • o.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(this.id < o.id 结果为正、this.id < o.id 结果为负,this.id = o.id 结果为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<E> set = new HashSet<E>();

说明: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());
		}
	}
}

输出结果:

集合的长度:5
Person [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值的元素属性。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • Java集合之Set接口及其实现类精解

    目录 Set接口概述 HashSet实现类 1.HashSet 具有以下特点: 2.HashSet 集合判断两个元素相等的标准 3.向HashSet中添加元素的过程 LinkedHashSet实现类 TreeSet实现类 Set接口概述 1.Set接口是Collection的子接口,set接口没有定义额外的方法,使用的都是Collection接口中的方法. 2.Set 集合不允许包含相同的元素,如果试把两个相同的元素加入同一个Set 集合中,则添加操作失败. 3.Set:存储无序的.不可重复的数

  • 浅析Java中的set集合类型及其接口的用法

    概念 首先,我们看看Set集合. (01) Set 是继承于Collection的接口.它是一个不允许有重复元素的集合. (02) AbstractSet 是一个抽象类,它继承于AbstractCollection,AbstractCollection实现了Set中的绝大部分函数,为Set的实现类提供了便利. (03) HastSet 和 TreeSet 是Set的两个实现类.     HashSet依赖于HashMap,它实际上是通过HashMap实现的.HashSet中的元素是无序的.   

  • java中set接口使用方法详解

    java中的set接口有如下的特点: 不允许出现重复元素: 集合中的元素位置无顺序: 有且只有一个值为null的元素. 因为java中的set接口模仿了数学上的set抽象,所以,对应的数学上set的特性为: 互异性:一个集合中,任何两个元素都认为是不相同的,即每个元素只能出现一次. 无序性:一个集合中,每个元素的地位都是相同的,元素之间是无序的.集合上可以定义序关系,定义了序关系后,元素之间就可以按照序关系排序.但就集合本身的特性而言,元素之间没有必然的序. 空集的性质:空集是一切集合的子集 S

  • Java使用PreparedStatement接口及ResultSet结果集的方法示例

    本文实例讲述了Java使用PreparedStatement接口及ResultSet结果集的方法.分享给大家供大家参考,具体如下: 说明: 1.PreparedStatement接口继承Statement,它的实例包含已编译的SQL语句,执行速度要快于Statement. 2.PreparedStatement继承了Statement的所有功能,三种方法executeUpdate.executeQuery.execute不再需要参数. 3.在JDBC应用中,一般都用PreparedStateme

  • 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

  • java中接口(interface)及使用方法示例

    1.接口:一种把类抽象的更彻底,接口里只能包含抽象方法的"特殊类".接口不关心类的内部状态数据,定义的是一批类所遵守的规范.(它只规定这批类里必须提供某些方法,提供这些方法就可以满足实际要求). 在JAVA编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明.一个类通过继承接口的方式,从而来继承接口的抽象方法. 接口并不是类,编写接口的方式和类很相似,但是它们属于不同的概念.类描述对象的属性和方法.接口则包含类要实现的方法. 除非实现接口的类是抽象类,否则该类

  • Java中常用修饰符的使用方法汇总

    修饰符汇总: 一:public protected default private 修饰类,修饰方法,修饰属性,修饰代码块. 类: 顶级类只能用public 修饰,顶级类不能使用private 和protected 修饰. 外部类可以被public修饰或者默认不写,不能用private和protected. 内部类可为静态,可用protected和private修饰. 方法: 通常方法可以被四个访问修饰符修饰,构造方法也可以被四个访问修饰符修饰. 抽象类中的抽象方法不能被private修饰,可以

  • java 中接口和抽象类的区别与对比

    java 中接口和抽象类的区别与对比 接口和抽象类的概念不一样. 接口是对动作的抽象,抽象类是对根源的抽象. 抽象类表示的是,这个对象是什么.接口表示的是,这个对象能做什么.比如,男人,女人,这两个类(如果是类的话--),他们的抽象类是人.说明,他们都是人. 人可以吃东西,狗也可以吃东西,你可以把"吃东西"定义成一个接口,然后让这些类去实现它. 所以,在高级语言上,一个类只能继承一个类(抽象类)(正如人不可能同时是生物和非生物),但是可以实现多个接口(吃饭接口.走路接口). 第一点:接

  • 详解Java中接口的定义与实例代码

    Java中接口的定义详解 1.定义接口 使用interface来定义一个接口.接口定义同类的定义类似,也是分为接口的声明和接口体,其中接口体由常量定义和方法定义两部分组成.定义接口的基本格式如下: [修饰符] interface 接口名 [extends 父接口名列表]{ [public] [static] [final] 常量; [public] [abstract] 方法; } 修饰符:可选,用于指定接口的访问权限,可选值为public.如果省略则使用默认的访问权限. 接口名:必选参数,用于

  • Java 中Object的wait() notify() notifyAll()方法使用

    Java 中Object的wait() notify() notifyAll()方法使用 一.前言 对于并发编程而言,除了Thread以外,对Object对象的wati和notify对象也应该深入了解其用法,虽然知识点不多. 二.线程安全基本知识 首先应该记住以下基本点,先背下来也无妨: 同一时间一个锁只能被一个线程持有 调用对象的wait()和notify()前必须持有它 三.wait()和notify()理解 3.1 wait()和notify()方法简介 wait()和notify()都是

  • java 中的封装介绍及使用方法

    java 中的封装介绍及使用方法 在面向对象程式设计方法中,封装(英语:Encapsulation)是指一种将抽象性函式接口的实现细节部份包装.隐藏起来的方法. 封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问. 要访问该类的代码和数据,必须通过严格的接口控制. 封装最主要的功能在于我们能修改自己的实现代码,而不用修改那些调用我们代码的程序片段. 适当的封装可以让程式码更容易理解与维护,也加强了程式码的安全性. 封装的优点 1. 良好的封装能够减少耦合. 2. 类内部

  • java中数组的定义及使用方法(推荐)

    数组:是一组相关变量的集合 数组是一组相关数据的集合,一个数组实际上就是一连串的变量,数组按照使用可以分为一维数组.二维数组.多维数组 数据的有点 不使用数组定义100个整形变量:int i1;int i2;int i3 使用数组定义 int i[100]; 数组定义:int i[100];只是一个伪代码,只是表示含义的 一维数组 一维数组可以存放上千万个数据,并且这些数据的类型是完全相同的, 使用java数组,必须经过两个步骤,声明数组和分配内存给该数组, 声明形式一 声明一维数组:数据类型

  • 详解java中接口与抽象类的区别

    详解java中接口与抽象类的区别 1.abstract class 在 Java 语言中表示的是一种继承关系,一个类只能使用一次继承关系.但是,一个类却可以实现多个interface. 2.在abstract class 中可以有自己的数据成员,也可以有非abstarct的成员方法,而在interface中,只能够有静态的不能被修改的数据成员(也就是必须是static final的,不过在 interface中一般不定义数据成员),所有的成员方法都是abstract的. 3.abstract c

  • java中Class.getMethods()和Class.getDeclaredMethods()方法的区别

    在java中,可以根据Class类的对象,知道某个类(接口)的一些属性(成员 ,方法,注释,注解)等.由于最近的工作中用到了这些,其中需要在代码中格局反射知道某些类的方法,查看文档的时候,看到了getMethods()和getDeclaredMethods()的差异.虽然两者都能实现目的,但个人觉得还是有必要区分下. JDK API(1.6)文档中是这样翻译两个方法的: getMethods(): 返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口(包括

随机推荐