JAVA深化_12——容器,Set接口介绍(HashSet,TreeSet)存储特征详解

Set接口介绍

Set接口继承自Collection接口,Set接口中没有新增方法,它和Collection接口保持完全一致。我们在前面学习List接口的使用方式,在Set中仍然适用。因此,学习Set的使用将没有任何难度。

Set接口特点

Set特点:无序、不可重复。无序指Set中的元素没有索引,我们只能遍历查找;不可重复指不允许加入重复的元素。更确切地讲,新元素如果和Set中某个元素通过equals()方法对比为true,则只能保留一个。

Set常用的实现类有:HashSet、TreeSet等,我们一般使用HashSet。

HashSet容器的使用

==HashSet是Set接口的实现类。==是Set存储特征的具体实现。

public class HashSetTest {
  public static void main(String[] args) {
    //实例化HashSet
    Set<String> set = new HashSet<>();
    //添加元素
    set.add("a");
    set.add("b1");
    set.add("c2");
    set.add("d");
    set.add("a");


    //获取元素,在Set容器中没有索引,所以没有对应的get(int index)方法
    for(String str: set){
      System.out.println(str);
     }
    System.out.println("--------------------");
    //删除元素
    boolean flag = set.remove("c2");
    System.out.println(flag);
    for(String str: set){
      System.out.println(str);
     }
    System.out.println("------------------------");
    int size = set.size();
    System.out.println(size);
   }
}

HashSet存储特征分析

HashSet 是一个不保证元素的顺序且没有重复元素的集合,是线程不安全的。HashSet允许有null 元素。

无序:

==在HashSet中底层是使用HashMap存储元素的。HashMap底层使用的是数组与链表实现元素的存储。==元素在数组中存放时,并不是有序存放的也不是随机存放的,而是对元素的哈希值进行运算决定元素在数组中的位置。

不重复:

当两个元素的哈希值进行运算后得到相同的在数组中的位置时,会调用元素的equals()方法判断两个元素是否相同。如果元素相同则不会添加该元素,如果不相同则会使用单向链表保存该元素。

通过HashSet存储自定义对象

<一定要重写自定义对象的HashCode()和equals()方法>

创建Users对象

public class Users {
  private String username;
  private int userage;


  public Users(String username, int userage) {
    this.username = username;
    this.userage = userage;
   }


  public Users() {
   }


  @Override
  public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;


    Users users = (Users) o;


    if (userage != users.userage) return false;
    return username != null ? username.equals(users.username) : users.username == null;
   }


  @Override
  public int hashCode() {
    int result = username != null ? username.hashCode() : 0;
    result = 31 * result + userage;
    return result;
   }


  public String getUsername() {
    return username;
   }


  public void setUsername(String username) {
    this.username = username;
   }


  public int getUserage() {
    return userage;
   }


  public void setUserage(int userage) {
    this.userage = userage;
   }


  @Override
  public String toString() {
    return "Users{" +
        "username='" + username + '\'' +
        ", userage=" + userage +
        '}';
   }
}

在HashSet中存储Users对象

public class HashSetTest2 {
  public static void main(String[] args) {
    //实例化HashSet
    Set<Users> set = new HashSet<>();
    Users u = new Users("zhangsan",18);
    Users u1 = new Users("zhangsan",18);
    set.add(u);
    set.add(u1);
    System.out.println(u.hashCode());
    System.out.println(u1.hashCode());
    for(Users users:set){
      System.out.println(users);
     }
   }
}


TreeSet容器的使用

TreeSet实现了Set接口,它是一个可以对元素进行排序的容器。底层实际是用TreeMap实现的,内部维持了一个简化版的TreeMap,通过key来存储元素。 TreeSet内部需要对存储的元素进行排序,因此,我们需要给定排序规则。

排序规则实现方式:

  • 通过元素自身实现比较规则。
  • 通过比较器指定比较规则。
public class TreeSetTest {
  public static void main(String[] args) {
    //实例化TreeSet
    Set<String> set = new TreeSet<>();
    //添加元素
    set.add("c");
    set.add("a");
    set.add("d");
    set.add("b");
    set.add("a");


    //获取元素
    for(String str :set){
      System.out.println(str);
     }
   }
}

通过元素自身实现比较规则

在元素自身实现比较规则时,需要实现Comparable接口中的compareTo方法,该方法中用来定义比较规则。TreeSet通过调用该方法来完成对元素的排序处理。

创建Users类

public class Users implements Comparable<Users>{
  private String username;
  private int userage;


  public Users(String username, int userage) {
    this.username = username;
    this.userage = userage;
   }


  public Users() {
   }


  @Override
  public boolean equals(Object o) {
    System.out.println("equals...");
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;


    Users users = (Users) o;


    if (userage != users.userage) return false;
    return username != null ? username.equals(users.username) : users.username == null;
   }


  @Override
  public int hashCode() {
    int result = username != null ? username.hashCode() : 0;
    result = 31 * result + userage;
    return result;
   }


  public String getUsername() {
    return username;
   }


  public void setUsername(String username) {
    this.username = username;
   }


  public int getUserage() {
    return userage;
   }


  public void setUserage(int userage) {
    this.userage = userage;
   }


  @Override
  public String toString() {
    return "Users{" +
        "username='" + username + '\'' +
        ", userage=" + userage +
        '}';
   }


  //定义比较规则
  //正数:大,负数:小,0:相等
  @Override
  public int compareTo(Users o) {
    if(this.userage > o.getUserage()){
      return 1;
     }
    if(this.userage == o.getUserage()){
      return this.username.compareTo(o.getUsername());
     }
    return -1;
   }
}

Set<Users> set1 = new TreeSet<>();
Users u = new Users("zhangsan",18);
Users u1 = new Users("zhouxinchi",22);
Users u2 = new Users("chenglong",22);
set1.add(u);
set1.add(u1);
set1.add(u2);
for(Users users:set1){
  System.out.println(users);
}

通过比较器实现比较规则

通过比较器定义比较规则时,我们需要单独创建一个比较器,比较器需要实现Comparator接口中的compare方法来定义比较规则。**在实例化TreeSet时将比较器对象交给TreeSet来完成元素的排序处理。**此时元素自身就不需要实现比较规则了。

创建Student类

public class Student {
  private String name;
  private int age;


  public Student(String name, int age) {
    this.name = name;
    this.age = age;
   }


  public Student() {
   }


  @Override
  public String toString() {
    return "Student{" +
        "name='" + name + '\'' +
        ", age=" + age +
        '}';
   }


  public String getName() {
    return name;
   }


  public void setName(String name) {
    this.name = name;
   }


  public int getAge() {
    return age;
   }


  public void setAge(int age) {
    this.age = age;
   }


  @Override
  public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;


    Student student = (Student) o;


    if (age != student.age) return false;
    return name != null ? name.equals(student.name) : student.name == null;
   }


  @Override
  public int hashCode() {
    int result = name != null ? name.hashCode() : 0;
    result = 31 * result + age;
    return result;
   }
}

创建比较器

public class StudentComparator implements Comparator<Student> {


  //定义比较规则
  @Override
  public int compare(Student o1, Student o2) {
    if(o1.getAge() > o2.getAge()){
      return 1;
     }
    if(o1.getAge() == o2.getAge()){
      return o1.getName().compareTo(o2.getName());
     }
    return -1;
   }
}

public class TreeSetTest3 {
  public static void main(String[] args) {
    //创建TreeSet容器,并给定比较器对象
    Set<Student> set = new TreeSet<>(new StudentComparator());
    Student s = new Student("zhangsan",18);
    Student s1 = new Student("zhouxinchi",22);
    Student s2 = new Student("sxtchenglong",22);
    set.add(s);
    set.add(s1);
    set.add(s2);
    for(Student student:set){
      System.out.println(student);
     }
   }
}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Java 基础核心总结》 Java 概述 什么是 Java2 Java 的特点Java 开发环境 JDK JRE Java 开发环境配置 Java 基本语法 数据类型基础语法运算符 Java 执行控制流程条件语句 if 条件语句 if...else 条件语句if...else if 多分支语句switch 多分支语句 循环语句 while 循环语句do...while 循环for 循环语句 跳转语句 break 语句 continue 语句面向对象 类也是-种对象对象的创建 属性和方法 构造方法 方法重载 方法的重写 初始化 类的初始化 成员初始化 构造器初始化初始化顺序 数组初始化 对象的销毁 对象作用域 this 和 super 访问控制权限继承 多态组合代理 向上转型static final 接口和抽象类接口 抽象类异常 认 识 Exception 什么是 Throwable 常见的 Exception 与 Exception 有关的 Java 关键字 throws 和 throw try 、finally 、catch 什么是 Error 内部类 创建内部类集合 Iterable 接口顶层接口 ArrayList Vector LinkedList 类Stack HashSet TreeSet LinkedHashSet 类 PriorityQueue HashMap TreeMap 类 LinkedHashMap 类 Hashtable 类IdentityHashMap 类WeakHashMap 类 Collections 类集合实现类特征图 泛形 泛型的使用 用泛型表示类 用泛型表示接口泛型方法 泛型通配符 反射 Class 类Field 类Method 类ClassLoader 类 枚举 枚举特性 枚举和普通类-样枚举神秘之处 枚举类 I/O File 类 基础 IO 类和相关方法InputStream OutputStream Reader 类Writer 类 InputStream 及其子类 OutputStream 及其子类Reader 及其子类Writer 及其子类 注解 关于 null 的几种处理方式大小写敏感 null 是任何引用类型的初始值 null 只是-种特殊的值使用 Null-Safe 方法null 判断 关于思维导图 Java.IO Java.lang Java.math Java.net Java 基础核心总结 V2.0 IO 传统的 BIO BIO NIO 和 AIO 的区别什么是流 流的分类 节点流和处理流 Java IO 的核心类 File Java IO 流对象 字节流对象InputStream OutputStream 字符流对象Reader Writer 字节流与字符流的转换新潮的 NIO 缓冲区(Buffer)通道(Channel) 示例:文件拷贝案例 BIO 和 NIO 拷贝文件的区别操作系统的零拷贝 选择器(Selectors) 选择键(SelectionKey) 示例:简易的客户端服务器通信 集合 集合框架总览 -、Iterator Iterable ListIterator 二、Map 和 Collection 接口Map 集合体系详解 HashMap LinkedHashMap TreeMap WeakHashMap Hashtable Collection 集合体系详解 Set 接口 AbstractSet 抽象类SortedSet 接口HashSet LinkedHashSet TreeSet List 接口 AbstractList 和 AbstractSequentialList Vector Stack ArrayList LinkedList Queue接口Deque 接口 AbstractQueue 抽象类LinkedList ArrayDeque PriorityQueue 反射的思想及作用 反射的基本使用 获取类的 Class 对象构造类的实例化对象获取-个类的所有信息 获取类中的变量(Field) 获取类中的方法(Method) 获取类的构造器(Constructor) 获取注解 通过反射调用方法反射的应用场景 Spring 的 IOC 容器反射 + 抽象工厂模式 JDBC 加载数据库驱动类反射的优势及缺陷 增加程序的灵活性破坏类的封装性 性能损耗 代理模式 静态代理与动态代理常见的动态代理实现JDK Proxy CGLIB JDK Proxy 和 CGLIB 的对比动态代理的实际应用 Spring AOP 变量 变量汇总实例变量 实例变量的特点全局变量 静态变量 静态变量的特点类变量 局部变量

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值