第18章 集合框架(2)-Set接口
第18章 集合框架(2)-Set接口
Set是Collection子接口,模拟了数学上的集的概念
Set集合存储特点
1.不允许元素重复
2.不会记录元素的先后添加顺序
Set只包含从Collection继承的方法,不过Set无法记住添加的顺序,不允许包含重复的元素,当试图添加两个相同元素进Set集合,添加操作会失败,add()方法返回false
Set判断两个对象是否相等用equals,而不是用===,也就是说两个对象equals比较返回true,Set集合是不会接受新添加的这个对象的。
1.HashSet类
1.1.equals方法和hashCode方法
HashSet是Set接口最常用的实现类,顾名思义,底层采用了哈希表(散列/hash)算法
其实底层也是一个数组,存在的意义是提供查询速度,插入速度也比较快,但是适用于少量数据的插入操作
在HashSet中如何判断两个对象是否相等问题
1.两个对象的equals比较相等,返回true,则说明是相同对象。
2.两个对象的hashCode方法返回值相等。
以上两个条件都要满足才能说明两个对象是相等的
对象的hashCode值决定了在哈希表中的存储位置
而这缺一不可
在往HashSet集合中添加新的对象的时候,先回判断该对象中的hashCode值:
1.不等:直接把该新的对象存储到hashCode指定的位置
2.相等:在继续判断该对象和集合中的对象的equals作比较
2.1.hashCode相同,equals为true,则视为是同一个对象,则保存在哈希表中
2.2.hashCode相同,equals为false,非常麻烦,存储在之前对象同槽位的链表上(拒绝,操作比较麻烦)
对象的hashCode和equals方法的重要性
每一个存储到hash表中的对象,都的提供hashCode和equals方法,用来判断是否是同一个对象
存储在哈希表中的对象,都应该覆盖equals方法和hashCod方法,并且保证equals相等的时候,hashCode也应该相等
1.2.hashSet集合常用方法
常用方法跟Vector类的相似,不再详细描述
2.LinkedHashSet类
之前我们已经学了两个接口
List接口:允许元素重复,记录先后顺序
Set接口:不允许元素重复,不记录先后顺序
但是有第三种需求:不允许元素重复,但是希望能够记录先后添加顺序,这就是LinkedHashSet类。
LinkedHashSet:底层采用哈希表和链表算法
哈希表:用来保证元素唯一性,此时就是HashSet,在哈希表中元素没有先后顺序
链表:来记录元素的先后添加顺序
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
/**
* 测试LinkedHashSet类记录顺序的功能
*/
public class TestLinkedHashSet {
//不记录先后顺序
public static void HashSetDemo(){
Set<String> set = new HashSet<>();
set.add("X");
set.add("C");
set.add("B");
set.add("1");
set.add("2");
System.out.println(set);//[1, B, 2, C, X]
}
public static void LinkedHashSetDemo(){
//记录先后顺序
Set<String> set = new LinkedHashSet<>();
set.add("X");
set.add("C");
set.add("B");
set.add("1");
set.add("2");
System.out.println(set);//[X, C, B, 1, 2]
}
public static void main(String[] args) {
HashSetDemo();
LinkedHashSetDemo();
}
}
3.TreeSet类
TreeSet类和Set接口的关系是:
TreeSet继承于NaviageableSet接口(可作范围查询集合),再继承于SortSet接口(可排序的集合),最后再继承Set接口
底层采用红黑树算法,会对存储的元素默认按照使用自然排序(从小到大):
必须保证TreeSet集合中的元素对象是同一种类型的对象。
例下面这个会报错
//编译之后会报错,A和1不是同类型,不能做对比
public class TestTreeSet {
public static void main(String[] args) {
TreeSet set = new TreeSet();
set.add("A");
set.add(1);
System.out.println(set);
}
如果是同类型的是可以的(此处是用泛型作的限定):
import java.util.TreeSet;
public class TestTreeSet {
public static void main(String[] args) {
TreeSet set = new TreeSet();
set.add("A");
set.add("D");
set.add("Y");
set.add("1");
set.add("6");
set.add("C");
System.out.println(set);//[1, 6, A, C, D, Y]
}
}
关于TreeSet类的一些方法:
除了一些通用的方法,这里再举例一些特殊的用法:
import java.util.TreeSet;
//验证TreeSet的方法
public class TestTreeSet {
public static void main(String[] args) {
TreeSet set = new TreeSet();
set.add("A");
set.add("D");
set.add("Y");
set.add("1");
set.add("6");
set.add("C");
System.out.println(set);//[1, 6, A, C, D, Y]
//first()返回第一个(最低)元素对象
System.out.println(set.first());//1
//last()返回最后面的一个,也就是最大的一个
System.out.println(set.last());//Y
//floor(E e)返回所有小于或等于给定的元素中的最大的一个对象
System.out.println(set.floor("C"));//C
//lower(E e)返回此 set 中严格小于给定元素的最大元素;如果不存在这样的元素,则返回 null。
System.out.println(set.lower("1"));//null
//ceiling(E e) 返回此 set 中大于等于给定元素的最小元素;如果不存在这样的元素,则返回 null。
System.out.println(set.ceiling("A"));//A
//tailSet(E fromElement)返回此 set 的部分视图,其元素大于等于 fromElement,其实就是给定元素之后的集合对象
System.out.println(set.tailSet("A"));//[A, C, D, Y]
}
}
以上的方法并不是全部,具体的可以查api
3.1.排序接口
TreeSet的排序规则有两种,一种是自然排序,一种是认为设定。这是TreeSet特有的,往TreeSet里存放元素的时候,必须要用compareTo方法,如果是自己写的对象,要在这个对象里面重写这个方法。
3.1.1.Comparable自然排序
自然排序:
TreeSet调用集合元素的compareTo方法来比较元素的大小关系,然后将集合元素按照升序排列(从小到大),要求TreeSet集合中元素得实现java.util.Comparable接口
自然排序是按Unicode编码排序。先排数字,然后大写字母,再小写字母,字符是按照字典顺序的,A,AB,AC,a
java.util.Comparable接口:可比较的
覆盖public int compareTo(Object o)方法,在该方法中编写比较规则。
在该方法中,比较当前对象(this)和参数对象o比较(严格上说比较的是对象中的数据,比如按照对象的年龄排序)。
this > 0;返回正整数.1
this < 0;返回负整数.-1
this == 0;返回0,此时认为两个对象为同一个对象
在TreeSet的自然排序中,认为如果两个对象作比较如果返回的是0,则认为是同一个对象
import java.util.Set;
import java.util.TreeSet;
//测试comparable自然排序方法
class Person implements Comparable<Person>{
private String name;
private int age;
public Person(String name, int age){
this.name = name;
this.age = age;
}
public String toString(){
return "Person [name="+ name +", age="+age+"]";
}
//编写比较规则
public int compareTo(Person other){
if (this.age > other.age){
return 1;
}else if (this.age < other.age){
return -1;
}else {
return 0;
}
}
}
public class TestTreeSet {
public static void main(String[] args) {
//按照Person对象的年龄做自然排序
Set<Person> set = new TreeSet<>();
set.add(new Person("Rocco",98));
set.add(new Person("Eric",32));
set.add(new Person("Ao",18));
set.add(new Person("Job",5));
System.out.println(set);//[Person [name=Job, age=5], Person [name=Ao, age=18], Person [name=Eric, age=32], Person [name=Rocco, age=98]]
}
}
3.1.2.Compartor定制排序
定制排序可以按照自己的需求来排序,比如下面的例子中是按照名字的长短来排序的。
在TreeSet构造器中传递到java.lang.Comparator对象,并覆盖public int compare(Object o1, Object o2)再编写比较规则
对于TreeSet集合来说,要么使用自然排序,要么使用定制排序。
判断两个对象是否相等的规则
自然排序:comparaTo返回0
定制排序:compare方法返回0
import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;
/**
* 测试定制排序方法
* 按照名字长短进行排序
*/
class Person {
String name;
int age;
public Person(String name, int age){
this.name = name;
this.age = age;
}
public String toString(){
return "Person [name="+ name +", age="+age+"]";
}
}
class NameLengthComparator implements Comparator<Person> {
@Override
public int compare(Person o1, Person o2) {
if (o1.name.length() > o2.name.length()){
return -1;
}else if (o1.name.length() < o2.name.length()){
return 1;
}else {
return 0;
}
}
}
public class TestTreeSet {
public static void main(String[] args) {
Set<Person> set2 = new TreeSet<>(new NameLengthComparator());
set2.add(new Person("Rocco",98));
set2.add(new Person("Eric",32));
set2.add(new Person("Ao",18));
set2.add(new Person("Job",5));
System.out.println(set2);//[Person [name=Rocco, age=98], Person [name=Eric, age=32], Person [name=Job, age=5], Person [name=Ao, age=18]]
}
}
4.Set实现性能分析
Set接口的实现类:
共同特点:
1.都不允许元素重复
2.都不是线程安全类
解决方法:Set s = Collections.synchronizedSet(Set对象);
HashSet:
不保证元素的先后添加顺序
底层采用的是哈熙表算法,查询效率极高。
判断两个对喜爱那个是否是否相等的规则:
1.equals比较true
2.hashCode值相同
要求:要求存在哈希中的对象元素都的覆盖equals和HashCode方法
LinkedHashSet
HashSet的子类,底层也采用的是哈希表算法,但是也使用了链表算法来维持元素的先后添加顺序
判断两个对象是否相等的规则和HashSet相同
因为需要多使用一个链表来记录元素的顺序,所以性能相对与HashSet较低
一般少用,如果要求一个集合既要保证元素不重复,又需要记录添加先后顺序,才选择使用LinkedHashSet
TreeSet
不保证元素的先后添加顺序,但是会对集合中的元素做排序操作
底层采用红黑树算法(树结构,比较擅长做范围查询)
TreeSet要么采用自然排序,要么定制排序
自然排序:要求在TreeSet集合中的对象必须实现java.lang.Comparable接口,并覆盖compareTo方法
定制排序:要求在构建TreeSet对象的时候,传入一个比较器对象(必须实现java.lang.Comparator接口)。在比较器中覆盖compare方法,并编写比较规则
TreeSet判断元素对象重复的规则
compareTo/compare方法是否返回0,如果返回0,则视为同一个对象
如何选用
HashSet做等值查询效率高,TreeSet做范围查询效率高
而我们更多的情况都是在做等值查询,在数据库的索引中做范围查询较多,所以数据结构主要用于做索引,用来提高查询效率
第18章 集合框架(2)-Set接口的更多相关文章
- 第19章 集合框架(3)-Map接口
第19章 集合框架(3)-Map接口 1.Map接口概述 Map是一种映射关系,那么什么是映射关系呢? 映射的数学解释 设A,B是两个非空集合,如果存在一个法则,使得对A中的每一个元素a,按法则f,在 ...
- JAVA基础第五章-集合框架Map篇
业内经常说的一句话是不要重复造轮子,但是有时候,只有自己造一个轮子了,才会深刻明白什么样的轮子适合山路,什么样的轮子适合平地! 我将会持续更新java基础知识,欢迎关注. 往期章节: JAVA基础第一 ...
- Java使用实现面向对象编程:第七章集合框架的解读=>重中之重
对于集合框架,是非常重要的知识,是程序员必须要知道的知识点. 但是我们为什么要引入集合框架呢? 我们之前用过数组存储数据,但是采用数组存储存在了很多的缺陷.而现在我们引用了集合框架,可以完全弥补了数组 ...
- Java集合框架之Collection接口
Java是一门面向对象的语言,那么我们写程序的时候最经常操作的便是对象了,为此,Java提供了一些专门用来处理对象的类库,这些类库的集合我们称之为集合框架.Java集合工具包位于Java.util包下 ...
- java 集合框架(二)Iterable接口
Iterable接口是java 集合框架的顶级接口,实现此接口使集合对象可以通过迭代器遍历自身元素,我们可以看下它的成员方法 修饰符和返回值 方法名 描述 Iterator<T> iter ...
- Java集合框架之四大接口、常用实现类
Java集合框架 <Java集合框架的四大接口> Collection:存储无序的.不唯一的数据:其下有List和Set两大接口. List:存储有序的.不唯一的数据: Set:存储无序的 ...
- Java集合框架之Map接口浅析
Java集合框架之Map接口浅析 一.Map接口综述: 1.1java.util.Map<k, v>简介 位于java.util包下的Map接口,是Java集合框架的重要成员,它是和Col ...
- Java集合框架之Set接口浅析
Java集合框架之Set接口浅析 一.java.util.Set接口综述: 这里只对Set接口做一简单综述,其具体实现类的分析,朋友们可关注我后续的博文 1.1Set接口简介 java.util.se ...
- Java集合框架之List接口浅析
Java集合框架之List接口浅析 一.List综述: 毫无疑问List接口位于java.util包下,继承自 Collection接口 存储元素的特点: 有序可重复(有序:即存进去是什么顺序,取出来 ...
随机推荐
- C#怎样保证弹出窗体是唯一并居中显示
Winform窗体中,假如我从Form1窗体要弹出Form2窗体,写法是这样的: Form2 f2 = new Form2(); f2.Show(); 1.如何使窗体打开时居中显示 //初始化默认窗体 ...
- WNMP集成环境下配置thinkPHP
在网上查了许多解决方法,下面是自己测试过能行的方法,只需在nginx.conf文件添加内容就可以了. 打开nginx.conf文件 ## Try the requested URI as files ...
- Ajax调用处理页面错误信息500的解决思路
最近在做项目的时候遇到一个问题:(李昌辉) 在本地服务器上做好之后,部署到阿里云虚拟主机,结果访问页面出现问题,由于登录使用的是AJAX调用处理页面,所以在点击登录的时候没有任何反应. 打开F12调试 ...
- 十一个行为模式之访问者模式(Visitor Pattern)
定义: 提供一个作用于某对象结构(通常是一个对象集合)的操作的接口,使得在添加新的操作或者在添加新的元素时,不需要修改原有系统,就可以对各个对象进行操作. 结构图: Visitor:抽象访问者类,对元 ...
- jquery限制文本框只能输入金额
$("#batch_diff_percent").keyup(function () { var reg = $(this).val().match(/\d+\.?\d{0,2}/ ...
- iOS如何用代码控制以不同屏幕方向打开新页面?
转载:http://blogread.cn/it/article/7765?f=wb#original 代码示例:https://github.com/johnlui/Swift-On-iOS/tre ...
- ArcGIS中的坐标系统定义与投影转换【转】
ArcGIS中的坐标系统定义与投影转换 坐标系统是GIS数据重要的数学基础,用于表示地理要素.图像和观测结果的参照系统,坐标系统的定义能够保证地理数据在软件中正确的显示其位置.方向和距离,缺少坐标系统 ...
- iOS9请求https问题-记录
iOS9 开始苹果将HTTP全改为HTTPS了,所以出现网络请求失败问题,解决办法: 1.改回HTTP: 在info.plist文件中添加一个Key:NSAppTransportSecurity(字典 ...
- iOS 学习 - 17.Socket
Socket 是应用层与 TCP / IP 协议通信的中间软件抽象层,它是一组接口 TCP:面向连接.传输可靠(保证数据正确性,保证数据顺序).用于传输大量数据(流模式).速度慢,建立连接需要开销 ...
- 通过LoadRunner - Analyze详细分析页面元素请求
众所周知LoadRunner录制某个链接,包括动态请求与js.css.jpg等静态请求. web_custom_request("动态请求", "URL=http://w ...