Java基础——Set接口

简介:   文章还按照上篇文章的UML图来分析:

  文章还按照上篇文章的UML图来分析:


30.png

Set和HashSet


 Set接口这一“派别”中,HashSet实现了Set接口,并且它还有一个子类LinkedHashSet。它们都根据对象的hashCode值来决定元素的存取位置,用equals方法来判断对象是否相等。所以重写对象equals方法时一定要根据实际场景重写hashCode方法。


 比如要判断是否是同一个人,判断他的身份证号是否相同就可以了,所以Person类可以用下面的方式重写equals方法和hashCode方法:


public class Person{ 
  private String idCard; 
  private String name; 
  @Override 
  public boolean equals(Object o) { 
    if (((Person)o).idCard.equals(idCard)){
      return true; 
    } 
    return false; 
  } 
}


 虽然HashSet和LinkedHashSet都是根据对象的hashCode值来决定元素的存取位置,但是LinkedHashSet同时也使用链表来维护存入对象的次序,使对象看起来像是顺序插入的,所以当遍历LinkedHashSet时,将以对象插入的次序访问。两者的区别可以用下图来表示:


31.png


 由于这种特性,使得LinkedHashSet迭代访问Set中元素时效率较HashSet高,但是增删元素的效率较低。



TreeSet


 实现了SortedSet接口的TreeSet显著的特点就是排序,相同类型的元素进行排序才有意义,所以TreeSet中存放的元素必须是相同类型的,否则会报java.lang.ClassCastException异常。


 之前没有太关注但它的功能很实用,这里多说两句~


 TreeSet支持两种排序方式,自然排序和自定义排序。默认是自定义排序。但是TreeSet排序的前提是其中的元素要实现Comparable接口,或者有一个自定义的比较器。


 比较常用的String、Date、Integer、Float、BigDecimal等类都实现了Comparable接口( 实现了它唯一的compareTo(T o) 方法 ),所以TreeSet对这些对象的排序都是默认的,而且是默认升序排列的。


 自然排序示例:


 添加实现了Comparable接口的元素:


  Set ts=new TreeSet(); 
  ts.add("helloworld"); 
  ts.add("apple"); 
  ts.add("danny"); 
  for (Iterator iterator = ts.iterator();
  iterator.hasNext();) { 
     System.out.println(iterator.next());
  }

  输出结果


apple 
danny 
helloworld 


  如果TreeSet中需要添加自定义对象,则需要自定义一个比较器(实现Comparator接口)。


  添加拥有比较器的元素


public class TreeSetTest{ 
  @Test 
  public void test(){ 
    TreeSet ts=new TreeSet(new Person.PersonCompare()); 
    Person p1=new Person("456","dannyhoo"); 
    Person p2=new Person("123","dannySong"); 
    ts.add(p1); 
    ts.add(p2); 
    for (Iterator iterator = ts.iterator(); iterator.hasNext();) { 
      System.out.println(((Person)iterator.next()).getName()); 
    } 
  } 
} 
class Person{ 
  private String idCard; 
  private String name; 
  public Person(String idCard,String name){ 
    this.idCard=idCard; this.name=name; 
  } 
  public String getIdCard() { 
    return idCard; 
  } 
  public void setIdCard(String idCard) { 
    this.idCard = idCard; 
  } 
  public String getName() { 
    return name;
  } 
  public void setName(String name) { 
    this.name = name; 
  } 
  static class PersonCompare implements Comparator{ 
    @Override 
    public int compare(Object o1, Object o2) { 
      Person p1=(Person)o1; 
      Person p2=(Person)o2; 
      return p1.idCard.compareTo(p2.idCard);//按照身份证号排序 
    } 
  } 
} 

  上面代码中的PersonCompare就是Person自己定义的比较器,需要实现Comparator接口并重写其compare接口,比较规则可以按照实际场景来定义。


相关文章
|
4天前
|
存储 Java 编译器
Java中的抽象类与接口,在阿里工作5年了
Java中的抽象类与接口,在阿里工作5年了
|
6天前
|
Java 开发者
Java一分钟之-Lambda表达式与函数式接口
【5月更文挑战第12天】Java 8引入的Lambda表达式简化了函数式编程,与函数式接口结合,实现了代码高效编写。本文介绍了Lambda的基本语法,如参数列表、箭头符号和函数体,并展示了如何使用Lambda实现`Runnable`接口。函数式接口仅有一个抽象方法,可与Lambda搭配使用。`@FunctionalInterface`注解用于确保接口具有单一抽象方法。文章还讨论了常见的问题和易错点,如非函数式接口、类型冲突以及Lambda表达式的局部变量可见性,并提供了避免这些问题的策略。通过理解Lambda和函数式接口,开发者能提高代码可读性和效率。
44 4
|
1天前
|
并行计算 Java API
Java 8中的接口默认方法和静态方法以及并行数组
【5月更文挑战第19天】Java 8引入了许多新特性,其中包括接口的默认方法和静态方法,以及并行数组的能力。这些特性增强了Java的面向对象编程模型和数组处理能力。让我们深入了解它们的概念和实践。
19 2
|
3天前
|
存储 Java
Java一分钟之-高级集合框架:Queue与Deque接口
【5月更文挑战第18天】本文探讨Java集合框架中的`Queue`和`Deque`接口,两者都是元素序列的数据结构。`Queue`遵循FIFO原则,主要操作有`add/remove/element/peek`,空队列操作会抛出`NoSuchElementException`。`Deque`扩展`Queue`,支持首尾插入删除,同样需注意空`Deque`操作。理解并正确使用这两个接口,结合具体需求选择合适数据结构,能提升代码效率和可维护性。
29 4
|
6天前
|
Java API 容器
Java8函数式编程接口:Consumer、Supplier、Function、Predicate
Java8函数式编程接口:Consumer、Supplier、Function、Predicate
8 1
|
6天前
|
Java ice
【Java开发指南 | 第二十九篇】Java接口
【Java开发指南 | 第二十九篇】Java接口
9 0
|
6天前
|
Java
【Java开发指南 | 第九篇】访问实例变量和方法、继承、接口
【Java开发指南 | 第九篇】访问实例变量和方法、继承、接口
15 4
|
6天前
|
安全 Java 调度
Java一分钟:多线程编程初步:Thread类与Runnable接口
【5月更文挑战第11天】本文介绍了Java中创建线程的两种方式:继承Thread类和实现Runnable接口,并讨论了多线程编程中的常见问题,如资源浪费、线程安全、死锁和优先级问题,提出了解决策略。示例展示了线程通信的生产者-消费者模型,强调理解和掌握线程操作对编写高效并发程序的重要性。
47 3
|
6天前
|
Java API
Java 接口
5月更文挑战第6天
|
6天前
|
存储 安全 Java
Java一分钟之-Map接口与HashMap详解
【5月更文挑战第10天】Java集合框架中的`Map`接口用于存储唯一键值对,而`HashMap`是其快速实现,基于哈希表支持高效查找、添加和删除。本文介绍了`Map`的核心方法,如`put`、`get`和`remove`,以及`HashMap`的特性:快速访问、无序和非线程安全。讨论了键的唯一性、`equals()`和`hashCode()`的正确实现以及线程安全问题。通过示例展示了基本操作和自定义键的使用,强调理解这些概念对编写健壮代码的重要性。
10 0