Java无序性和不可重复性的含义是什么?

在Java集合框架中,HashSet是一个典型的实现无序性和不可重复性的数据结构。为了更好地理解这两个概念的含义,我们需要深入了解HashSet的底层实现机制。

无序性

无序性并不等于随机性。无序性指的是存储的数据在底层数组中并非按照插入顺序进行存储,而是根据数据的哈希值决定其存储位置。

示例代码:

java

import java.util.HashSet;
import java.util.Iterator;

public class HashSetExample {
    public static void main(String[] args) {
        HashSet<String> set = new HashSet<>();
        set.add("one");
        set.add("two");
        set.add("three");
        set.add("four");

        Iterator<String> iterator = set.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
}

执行上述代码,输出结果可能是:

txt

one
two
three
four

也可能是其他顺序。可以看到,元素输出的顺序并不是按照插入的顺序,这是因为HashSet底层使用了哈希表来存储数据,具体存储位置由哈希值决定。

不可重复性

不可重复性是指在HashSet中添加的元素不能重复。判断重复的依据是equals()方法返回true,以及hashCode()方法值相同。因此,为了保证HashSet能正确判断元素的唯一性,必须同时重写equals()方法和hashCode()方法。

示例代码:

java

import java.util.HashSet;
import java.util.Objects;

public class HashSetExample {
    public static void main(String[] args) {
        HashSet<Person> set = new HashSet<>();
        set.add(new Person("John", 25));
        set.add(new Person("John", 25)); // 这将不会被添加,因为equals和hashCode相同

        for (Person person : set) {
            System.out.println(person);
        }
    }
}

class Person {
    private String name;
    private int age;

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

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

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

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

在上述代码中,我们重写了Person类的equals()hashCode()方法。由于两个Person对象的nameage属性相同,因此它们被认为是相同的对象,不会被重复添加到HashSet中。

深入源码解析

为了更深入地理解无序性和不可重复性,我们来看一下HashSet的源码实现。

HashSet实际上是基于HashMap实现的。每次我们向HashSet中添加元素,内部都会调用HashMapput方法。

HashSet源码片段:

java

public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, java.io.Serializable {
    private transient HashMap<E,Object> map;

    // Dummy value to associate with an Object in the backing Map
    private static final Object PRESENT = new Object();

    public HashSet() {
        map = new HashMap<>();
    }

    public boolean add(E e) {
        return map.put(e, PRESENT) == null;
    }
}

HashSet中,每个元素作为HashMap的键,而一个固定的对象PRESENT作为值。因此,HashSetadd方法实际上调用了HashMapput方法。

HashMap的put方法:

java

public V put(K key, V value) {
    if (key == null)
        return putForNullKey(value);
    int hash = hash(key.hashCode());
    int i = indexFor(hash, table.length);
    for (Entry<K,V> e = table[i]; e != null; e = e.next) {
        Object k;
        if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
            V oldValue = e.value;
            e.value = value;
            e.recordAccess(this);
            return oldValue;
        }
    }

    modCount++;
    addEntry(hash, key, value, i);
    return null;
}

在这个方法中,首先计算键的哈希值,并通过哈希值找到对应的桶位置。如果桶中已经存在相同哈希值且equals方法返回true的键,则更新值,否则创建新的Entry并插入到桶中。

通过这个源码解析,我们可以更好地理解HashSet如何实现无序性和不可重复性。

实际应用场景

  1. 去重: 当我们需要一个不包含重复元素的集合时,HashSet是一个理想的选择。例如,统计一篇文章中的唯一单词。
  2. 快速查找: HashSet提供了常数时间复杂度的查找操作,因此在需要频繁查找操作的场景中,HashSet性能非常高效。

示例代码:

java

import java.util.HashSet;

public class UniqueWords {
    public static void main(String[] args) {
        String text = "This is a test. This test is only a test.";
        String[] words = text.split("\\W+");
        HashSet<String> uniqueWords = new HashSet<>();

        for (String word : words) {
            uniqueWords.add(word.toLowerCase());
        }

        System.out.println("Unique words: " + uniqueWords);
    }
}

在这个示例中,我们通过HashSet来统计一篇文章中的唯一单词,大大简化了代码复杂度,并且保证了高效的性能。

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值