Set 接口及其常用方法

Set接口是Collection接口的一个子接口,其主要特点如下:

  1. 不允许重复元素:Set接口的实现类不会包含重复的元素。更正式地说,不包含任何一对使得e1.equals(e2)成立的元素e1e2,并且最多只能有一个null元素。当尝试添加重复元素时,添加操作将被忽略。

  2. 无序性:Set接口取出元素的顺序和添加元素的顺序不一致(但是每次取出的顺序是固定的),即无法通过索引访问Set中的元素。

Set接口的常用实现类有HashSetTreeSetLinkedHashSet。可以使用迭代器和增强 for 循环遍历元素,但是不能使用普通 for 循环(不能使用索引)。下面的代码以其实现类HashSet演示Set接口的特点。

public class TestSet() {
  public static void main(String[] args) {
    Set set = new HashSet();
    set.add("Phoebe");
    set.add("Monica");
    set.add("Phoebe"); // 重复
    set.add("Ross");
    set.add("Chandler");
    set.add("Rachel");
    set.add(null);
    set.add(null); // 再次添加 null
    // 10 次输出结果均为:set=[Phoebe, null, Rachel, Ross, Chandler, Monica]
    // 重复的 Phoebe 和 null 都只输出了一个,
    // 取出顺序和添加顺序不一致但每次取出顺序都是相同的。
    for (int i = 0; i < 10; i++) {
      System.out.println("set=" + set);
    }
  }
}

注意:如果Set集合的元素是可变对象时,必须要小心。如果以影响equals()方法比较结果的方式修改Set中的元素的值,集合的行为是未指定的。这种情况的特例是Set不能将自身作为元素。以下以一个简单的 Person 类来测试修改HashSet中元素的值使得两个元素equals()方法比较结果相同时的情况。

public class Person {
  private String name;
  
  public Person() {
  }

  public Person(String name) {
    this.name = name;
  }

  public String getName() {
    return name;
  }

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

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

  @Override
  public int hashCode() {
    return Objects.hash(name);
  }

  @Override
  public String toString() {
    return "Person{" +
      "name='" + name + '\'' +
      '}';
  }
}
public class TestModifyValue() {
  public static void main(String[] args) {
    Set set = new HashSet();
    
    // 创建 3 个 Person 实例,其中 rose1.equals(rose2) 成立
    Person jack = new Person("Jack");
    Person rose1 = new Person("Rose");
    Person rose2 = new Person("Rose");
    // 将其添加到 set 中
    set.add(jack);
    set.add(rose1);
    set.add(rose2);
    
    // 可以看到只添加成功一个姓名为 Rose 的 Person 实例,其应为 rose1。
    System.out.println("set = " + set); // set = [Person{name='Rose'}, Person{name='Jack'}]

    // 将 set 添加到自身中,未添加成功
    set.addAll(set);
    System.out.println("set = " + set); // set = [Person{name='Rose'}, Person{name='Jack'}]

    // 将 rose1 的 name 属性修改为 Jack
    rose1.setName("Jack");
    System.out.println(rose1.equals(jack)); // true
    // 可以看到此时 set 集合中仍有两个对象,其 equals() 方法比较结果相同。
    System.out.println("set = " + set); // set = [Person{name='Jack'}, Person{name='Jack'}]
  }
}

Set 接口常用方法

Set接口和List接口一样,也是Collection接口的子接口,因此常用方法和Collection接口一样。但需要注意由于Set接口不包含重复元素,所以addAll()方法的参数也是Set时,addAll操作会有效地修改该集合,使其值为两个集合的并集

public class SetAddAll() {
  public static void main(String[] args) {
    Set set = new HashSet();
    set.add("Phoebe");
    set.add("Monica");
    set.add("Ross");
    System.out.println("set = " + set); // set = [Phoebe, Ross, Monica]

    Set set1 = new HashSet();
    set1.add("Phoebe");
    set.add("Chandler");

    set.addAll(set1);
    System.out.println("set = " + set); // set = [Phoebe, Ross, Chandler, Monica]
  }
}

Set 接口遍历元素方式

Set接口遍历元素的方式和Collection接口的一样,可以使用迭代器和增强 for 循环来遍历元素,但不能通过索引的方式来遍历元素。

public class SetThroughElements() {
  public static void main(String[] args) {
    Set set = new HashSet();
    set.add("Phoebe");
    set.add("Monica");
    set.add("John");

    System.out.println("---使用迭代器---");
    Iterator iterator = set.iterator();
    while (iterator.hasNext()) {
      Object obj =  iterator.next();
      System.out.println("obj = " + obj);
    }

    System.out.println("---使用增强 for---");
    for (Object o :set) {
      System.out.println("o = " + o);
    }

    // 不能使用普通 for 循环,因为 Set 不支持索引
  }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

野生的狒狒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值