第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接口的更多相关文章

  1. 第19章 集合框架(3)-Map接口

    第19章 集合框架(3)-Map接口 1.Map接口概述 Map是一种映射关系,那么什么是映射关系呢? 映射的数学解释 设A,B是两个非空集合,如果存在一个法则,使得对A中的每一个元素a,按法则f,在 ...

  2. JAVA基础第五章-集合框架Map篇

    业内经常说的一句话是不要重复造轮子,但是有时候,只有自己造一个轮子了,才会深刻明白什么样的轮子适合山路,什么样的轮子适合平地! 我将会持续更新java基础知识,欢迎关注. 往期章节: JAVA基础第一 ...

  3. Java使用实现面向对象编程:第七章集合框架的解读=>重中之重

    对于集合框架,是非常重要的知识,是程序员必须要知道的知识点. 但是我们为什么要引入集合框架呢? 我们之前用过数组存储数据,但是采用数组存储存在了很多的缺陷.而现在我们引用了集合框架,可以完全弥补了数组 ...

  4. Java集合框架之Collection接口

    Java是一门面向对象的语言,那么我们写程序的时候最经常操作的便是对象了,为此,Java提供了一些专门用来处理对象的类库,这些类库的集合我们称之为集合框架.Java集合工具包位于Java.util包下 ...

  5. java 集合框架(二)Iterable接口

    Iterable接口是java 集合框架的顶级接口,实现此接口使集合对象可以通过迭代器遍历自身元素,我们可以看下它的成员方法 修饰符和返回值 方法名 描述 Iterator<T> iter ...

  6. Java集合框架之四大接口、常用实现类

    Java集合框架 <Java集合框架的四大接口> Collection:存储无序的.不唯一的数据:其下有List和Set两大接口. List:存储有序的.不唯一的数据: Set:存储无序的 ...

  7. Java集合框架之Map接口浅析

    Java集合框架之Map接口浅析 一.Map接口综述: 1.1java.util.Map<k, v>简介 位于java.util包下的Map接口,是Java集合框架的重要成员,它是和Col ...

  8. Java集合框架之Set接口浅析

    Java集合框架之Set接口浅析 一.java.util.Set接口综述: 这里只对Set接口做一简单综述,其具体实现类的分析,朋友们可关注我后续的博文 1.1Set接口简介 java.util.se ...

  9. Java集合框架之List接口浅析

    Java集合框架之List接口浅析 一.List综述: 毫无疑问List接口位于java.util包下,继承自 Collection接口 存储元素的特点: 有序可重复(有序:即存进去是什么顺序,取出来 ...

随机推荐

  1. asp.net mvc项目自定义区域

    前言 直接上干货就是,就不废话了. 使用场景:分离模块,多站点等~~ 一.分离模块 自定义视图引擎,设置视图路径格式 项目结构图 1.Code: 在Global.asax Application_St ...

  2. C#枚举、结构、数组、排序

  3. 复选框(checkox)全选、全不选、反选、获得选中项值的用例

    HTML部分: <div class="all"> <ul> <li><input type="checkbox" v ...

  4. jQuery插件之——简单日历

    最近在研究js插件的开发,以前看大神们,对插件都是信手拈来,随便玩弄,感觉自己要是达到那种水平就好了,就开始自己研究插件开发了.研究了一段时间之后,就开始写了自己的第一个日历插件,由于是初学插件开发, ...

  5. UITableViewHeaderFooterView的封装

    UITableViewHeaderFooterView的封装 特点 1. 封装的 UITableViewHeaderFooterView 能够让用户更好的自定义自己的 headerView; 2. 封 ...

  6. ThingkPHP对数据库进行改操作

    public function test_check(){ $Experiment = M("Experiment");//实例化Experiment对象.这个对象是跟数据库的表对 ...

  7. Java打印九九乘法表

    package com.czgo; /** * 九九乘法表 * * @author AlanLee * */ public class Print99 { public static void mai ...

  8. centos为用户增加ssh key

    linux增加用户,为用户增加key 可以用  ssh-keygen -t rsa 添加ssh的key,会得到public_key和自己的private_key 然后这个key可以用在任何用户上 ad ...

  9. 全新的membership框架Asp.net Identity(1)——.Net membership的历史

    在Asp.net上,微软的membershop框架经历了Asp.net membership到Asp.net simple membership,再到现在的Asp.net Identity. 每一次改 ...

  10. Linux 克隆虚拟机引起的“Device eth0 does not seem to be present, delaying initialization”

    虚拟机Vmware上克隆了一个Red Hat Enterprise Linx启动时发现找不到网卡,如下所示,如果你在命令窗口启动网络服务就会遇到"Device eth0 does not s ...