JAVA基础-集合Set

Posted 不愿透露姓名的王建森

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JAVA基础-集合Set相关的知识,希望对你有一定的参考价值。

首先总结一下集合的体系:

集合 的体系:
------------| Collection 单例集合的根接口
----------------| List 如果是实现了List接口的集合类,具备的特点: 有序,可重复。
-------------------| ArrayList 底层是维护了一个Object数组实现的。 特点: 查询速度快,增删慢。
-------------------| LinkedList 底层是使用了链表数据结构实现的, 特点: 查询速度慢,增删快。
-------------------| Vector(了解即可) 底层也是维护了一个Object的数组实现的,实现与ArrayList是一样的,但是Vector是线程安全的,操作效率低。

----------------| Set 如果是实现了Set接口的集合类,具备的特点: 无序,不可重复。
-------------------| HashSet 底层是使用了哈希表来支持的,特点: 存取速度快.
-------------------| TreeSet 如果元素具备自然顺序 的特性,那么就按照元素自然顺序的特性进行排序存储。

Set

Set 集合,元素是无序的,而且不能重复的。

重点掌握 HashSet 实现类的使用。

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

public class SetDemo {

	public static void main(String[] args) {
		Set s1=new HashSet<>();
		s1.add("ddd");
		s1.clear();
		s1.remove("ddd");
		Iterator i1 = s1.iterator();
	}
}

HashSet

HashSet的特点:

  1. 添加的元素是无序的。

  2. HashSet 不是同步的,如果多个线程同时访问一个 HashSet,比如在修改时,一定要手动通过代码来保证同步,也就是保证安全。

  3. 集合元素值可以是 null

一些基本的用法:

import java.util.HashSet;
import java.util.Iterator;

public class HashSetDemo {

	public static void main(String[] args) {
		//hashset  存储数据唯一(不可重复)   无序
		HashSet<String> hs=new HashSet<String>();
		hs.add("张三");
		hs.add("张三");
		
		System.out.println(hs);
		System.out.println(hs.size());
		
		//遍历  foreach   迭代器
		for (String string : hs) {
			System.out.println("foreach:"+string);
		}
		//
		Iterator<String> i1=hs.iterator();
		while(i1.hasNext()) {
			System.out.println("迭代器:"+i1.next());
		}
		
	}
}

另外,我们从下面的代码可以看出一些hashset的特性,在这里,我们想要让hashset存储数据时不重复存储(因为每new一个对象,其索引不一样,且hash值也不同,即使我们new出的两个对象包含同样的信息,hashset依然会判定为两个不同的对象),我们做两个操作:

  1. 重写public boolean equals(Object obj)方法

  2. 重写public int hashCode() 方法

这么做的原因是:
往 HashSet 集合中添加一个元素的时候,默认调用 hashCode() 方法得到该对象的 hashCode 值,用于决定该对象在 HashSet 中存放的位置。
如果两个元素,通过 equals() 方法比较返回 true,但 hashCode() 返回的值不一样,说明两个元素是不 一样的,则允许添加。
所以,HashSet 集合判断两个元素是否相等,就是通过 equals() 方法还有 hashCode 值也一起比较。将来,如果有需要自定义一些判断方法,则可以模仿这里的操作方式。

import java.util.HashSet;

//人类
public class Person{

	String name;
	int age;
	String sex;

	public Person(String name, int age, String sex) {
		super();
		this.name = name;
		this.age = age;
		this.sex = sex;
	}
    
	@Override
	public int hashCode() {
	// TODO Auto-generated method stub
		return age;
	}
    
	//案例 主要对象中姓名 年龄  和性别是相同的 就判断同一个对象使用set保存后体现唯一性
	//根据性别 姓名 年龄
	@Override
	public boolean equals(Object obj) {
		Person p1=(Person) obj;
		if(this.sex.equals(p1.sex)) {
			if(this.name.equals(p1.name)) {
				if(this.age==p1.age) {
					return true;
				}
			}
		}

		return  false;
	}
	//alt +Shift+s 弹出窗口 
	public static void main(String[] args) {
		//需求 使用hashset集合 存储4个person对象 并打印输出出来 哈希吗值也有关系
		HashSet<Person> phSet=new HashSet<Person>();
		Person zhangsan=new Person("张三", 18, "男");
		Person zhangsan2=new Person("张三", 18, "男");

		Person lisi=new Person("李四", 18, "男");
		Person wangwu=new Person("王五", 18, "男");
		Person qianliu=new Person("钱六", 18, "男");
		phSet.add(zhangsan);
		phSet.add(lisi);
		phSet.add(wangwu);
		phSet.add(qianliu);
		phSet.add(zhangsan2);
		System.out.println(phSet);
	}

	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + ", sex=" + sex + "]";
	}
}

LinkedHashSet

LinkedHashSet 从名字上看,跟“链式”有关,它也是根据元素的 hashCode 值来决定元素的存储位置, 但还多使用链表来维护元素的顺序。

访问它的时候,会根据元素的添加顺序来访问集合中的元素,有个好处,访问时的性能会很好。

因为是链式的结构,在插入数据的时候,性能略差于 HashSet,插入元素时不建议使用。

import java.util.LinkedHashSet;

public class LinkedHashSetDemo {

	public static void main(String[] args) {
		//无序  唯一的
		//链表结构与哈希吗值都有关系
		//与hashset相比  访问快  插入慢
		//方法同 hashset一样用
		LinkedHashSet<String> lhs =new LinkedHashSet<String>();
		lhs.add("张三");
		lhs.add("张三");
		lhs.add("张三");
		lhs.add("张三");
		lhs.add("张三");
		System.out.println(lhs);
//		lhs.remove("zhangsan");
		
	}
}

public class TreeSetTest { 
    public static void main(String[] args) { 
        TreeSet nums = new TreeSet(); 
        // 向 TreeSet 中添加对象 
        nums.add(5); 
        nums.add(2); 
        nums.add(10); 
        nums.add(-9); 
        // 输出集合元素,看到集合元素已经处于排序状态 
        // 并没有按添加的先后顺序进行排列
        System.out.println(nums);
        // 输出集合里的第一个元素 
        System.out.println(nums.first()); 
        // 输出-9 
        // 输出集合里的最后一个元素 
        System.out.println(nums.last()); 
        // 输出10 
        // 返回小于4的子集,不包含4 (左闭右开)
        System.out.println(nums.headSet(4)); 
        // 输出[-9, 2] 
        // 返回大于5的子集,如果Set中包含5,子集中还包含5 (左闭右开)
        System.out.println(nums.tailSet(5)); 
        // 输出 [5, 10] 
        // 返回大于等于-3,小于4的子集。 
        // -3 < x < 4 
        System.out.println(nums.subSet(-3, 4)); 
        // 输出[2] 
    } 
}

TreeSet

不同于hashset是根据哈希值来存储元素,TrerSet借助了红黑树来存储对象,虽然不可索引,但是内部依然是按顺序排列的。

TreeSet 可保证元素处于排序的状态,所以 TreeSet 采用的是红黑树的数据结构来存储集合元素的。

排序规则有:自然排序(默认)和定制排序。

import java.util.TreeSet;

public class TreeSetDemo {

	public static void main(String[] args) {
		//存储红黑二叉树数据结构 会对数进行排序存储
		TreeSet ts=new TreeSet();
		ts.add(222);
		ts.add(13);
		ts.add(2);
		ts.add(33);
		ts.add(4);
		ts.add(1);
		System.out.println(ts);
		System.out.println("最高的"+ts.last());
		System.out.println("最小的"+ts.first());
		System.out.println("检索最小元素返回并删除"+ts.pollFirst());
		System.out.println("检索最大元素返回并删除"+ts.pollLast());
		System.out.println(ts);
		//遍历 foreach  迭代器
		
	}
}

TreeSet 会调用 compareTo(Object obj) 方法来比较元素之间的大小关系,按升序进行排列。

此方法属于 Comparable 接口,将返回一个整数值,实现该接口的类就可以用返回值来比较大小。

Comparable 接口,主要提供了比较大小的标准,有些将来会碰到的常用类:BigDecimal、 BigInteger、Character、Boolean、String 、Date、Time 等。 当我们在Treeset中插入一个我们自己写的对象的时候会报错,其原因就是TreeSet利用compareTo(Object obj) 方法来比较元素之间的大小,所以我们需要将我们要比较的对象实现Comparable 接口。

当 TreeSet 添加元素时,会调用 compareTo() 方法先去比较大小和根据红黑树去查找位置,如果通过

compareTo() 方法比较相等,就不能再添加了,所以下面的代码Set中只有一个元素。

下面是我们要放入TreeSet的对象,我们实现了Comparable<T>方法:

import java.util.Comparator;

public class Pet implements Comparable<Pet>{

	String name;
	String color;
	int age;
	public Pet(String name, String color, int age) {
		super();
		this.name = name;
		this.color = color;
		this.age = age;
	}
	@Override
	public String toString() {
		return "Pet [name=" + name + ", color=" + color + ", age=" + age + "]";
	}
	//treeset比较方法  原理红黑二叉树数据结构
	@Override
	public int compareTo(Pet o) {
		return 0;
	}
}
import java.util.TreeSet;

public class TreeSetDemo2 {

	public static void main(String[] args) {
		TreeSet<Pet> ts=new TreeSet<Pet>();
		ts.add(new Pet("妮妮", "白色", 18));
		ts.add(new Pet("妮妮", "白色", 18));

		System.out.println(ts);
	}
}

同时呢,如果想要实现我们自定义的排序方式,可以利用内部类的方法来实现:

import java.util.Comparator;
import java.util.TreeSet;

public class Pet2 {

	int age;
	
	
	public Pet2(int age) {
		super();
		this.age = age;
	}
	
	@Override
	public String toString() {
		return "Pet2 [age=" + age + "]";
	}

	//
	
	public static void main(String[] args) {
//		TreeSet<Pet2> treeSet=new TreeSet<Pet2>();
//		treeSet.add(new Pet2(18));
//		treeSet.add(new Pet2(17));
//		treeSet.add(new Pet2(2));
//		System.out.println(treeSet);
		//方式2  定制排序
		TreeSet<Pet2> t2=new TreeSet<Pet2>(new Comparator<Pet2>() {

			@Override
			public int compare(Pet2 o1, Pet2 o2) {
				// TODO Auto-generated method stub
				//比较
				return o1.age>o2.age?-1:o1.age<o2.age?1:0;
			}
		});
		
		//降序
		t2.add(new Pet2(18));
		t2.add(new Pet2(1));
		t2.add(new Pet2(23));
		System.out.println(t2);
	}

}










以上是关于JAVA基础-集合Set的主要内容,如果未能解决你的问题,请参考以下文章

代码片段 - Golang 实现集合操作

Java零基础学习(Set集合)

Java基础_Set集合

Java基础-集合框架之Set

197 01 Android 零基础入门 03 Java常用工具类 04 Java集合 03 Set集合 01 Set概述

JAVA基础-集合Set