欢迎访问悦橙教程(wld5.com),关注java教程。悦橙教程  java问答|  每日更新
页面导航 : > > 文章正文

Core Java Tutorial -,corejavatutorial

来源: javaer 分享于  点击 41521 次 点评:121

Core Java Tutorial -,corejavatutorial


Java HashSet 是 Set 接口最流行的实现。 java.util.HashSet 由一个HashMap 支持。HashSet 继承 AbstractSet 类并实现SetCloneableSerializable接口。

1. Java HashSet

Java 中有关 HashSet 的一些重点有:

Java HashSet Constructors

Java HashSet 提供四个构造器:
1. public HashSet():创建一个新的空的 HashSet,由默认初始容量为 16,加载因子为 0.75 的 HashMap 支持。
2. public HashSet(int initialCapacity):创建一个新的空的 HashSet,由指定初始容量,加载因子为 0.75 的 HashMap 支持。
3. public HashSet(int initialCapacity, float loadFactor)创建一个新的空的 HashSet,由指定初始容量,指定加载因子的 HashMap 支持。
4. public HashSet(Collection<? extends E> c):创建一个包含指定集合中元素的新 Set。 支持 HashMap 是使用默认加载因子(0.75)创建的,并且初始容量足以包含指定集合中的所有元素。

下面的代码片段显示了所有这些 HashSet 构造函数的示例用法。

package HashSet;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;

public class HashSetTest {
    public static void main(String[] args) {

        Set<String> set;

        //initial capacity should be power of 2
        set = new HashSet<>(32);

        //setting backing HashMap initial capacity and load factor
        set = new HashSet<>(32, 0.80f);

        //creating HashSet from another Collection
        Set<String> set1 = new HashSet<>(set);
        Set<String> set2 = new HashSet<>(new ArrayList<>());
    }
}

Java HashSet Methods

一些有用的 HashSet 方法:
1. public boolean add(E e):将给定的元素添加到 Set 中(如果该元素在 Set 不存在的话)。此方法内部使用 equals() 方法来检查重复项,因此请确保你的对象正确定义 equals() 方法。
2. public void clear():删除 Set 中的所有元素。
3. public Object clone():返回 Set 示栗的浅拷贝。
4. public boolean contains(Object o):如果 Set 包含给定元素返回 true,否则返回 false。
5. public boolean isEmpty():如果 Set 不包含任何元素,则返回 true,否则返回 false。
6. public Iterator<E> iterator():返回此 Set 中元素的迭代器。元素以特定顺序返回。
7. public boolean remove(Object o):从此 Set 中移除给定元素,如果存在则返回 true。如果元素不在集合中,则返回 false。
8. public int size():返回 Set 中元素的数量。
9. public Spliterator<E> spliterator():在此集合中的元素上创建一个后期绑定和快速失败的 Spliterator。这是在 Java 8 中引入的,但直到现在我都没用过他。
10. public boolean removeAll(Collection<?> c):HashSet 从 AbstractSet 继承此方法。此方法将删除属于指定集合一部分的集合中的所有元素。

Java HashSet Example

Java HashSet 示栗程序展示了 HashSet 的通常用法。

package HashSet;

import java.util.*;

public class HashSetExample {

    public static void main(String[] args) {
        Set<String> fruits = new HashSet<>();

        // add example
        fruits.add("Apple");
        fruits.add("Banana");

        // isEmpty example
        System.out.println("fruits set is empty = " + fruits.isEmpty());

        // contains example
        System.out.println("fruits contains Apple = " + fruits.contains("Apple"));
        System.out.println("fruits contains Mango = " + fruits.contains("Mango"));

        // remove example
        System.out.println("Apple removed from fruits set = " + fruits.remove("Apple"));
        System.out.println("Mango removed from fruits set = " + fruits.remove("Mango"));

        // size example
        System.out.println("fruits set size = " + fruits.size());

        // addAll example
        List<String> list = new ArrayList<>();
        list.add("Apple");
        list.add("Apple");
        list.add("Banana");
        list.add("Mango");

        System.out.println("fruits set before addAll = " + fruits);
        System.out.println("list = " + list);
        fruits.addAll(list);
        System.out.println("fruits set after addAll = " + fruits);

        // iterator example
        Iterator<String> iterator = fruits.iterator();
        while (iterator.hasNext()) {
            System.out.println("Consuming fruit " + iterator.next());
        }

        // removeAll example
        fruits.add("Orange");
        System.out.println("fruits set before removeAll = " + fruits);
        System.out.println("list = " + list);
        fruits.removeAll(list);
        System.out.println("fruits set after removeAll = " + fruits);

        // clear example
        fruits.clear();
        System.out.println("fruits set is empty = " + fruits.isEmpty());


    }
}

上面的 HashSet 示例程序的输出如下

fruits set is empty = false
fruits contains Apple = true
fruits contains Mango = false
Apple removed from fruits set = true
Mango removed from fruits set = false
fruits set size = 1
fruits set before addAll = [Banana]
list = [Apple, Apple, Banana, Mango]
fruits set after addAll = [Apple, Mango, Banana]
Consuming fruit Apple
Consuming fruit Mango
Consuming fruit Banana
fruits set before removeAll = [Apple, Mango, Orange, Banana]
list = [Apple, Apple, Banana, Mango]
fruits set after removeAll = [Orange]
fruits set is empty = true

Java HashSet ConcurrentModificationException Example

Java HashSet 迭代器是快速失败的,所以如果 Set 在结构上被修改,则方法将抛出 java.util.ConcurrentModificationException。下面是一个简单的例子来说明这一点。

package HashSet;

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

public class HashSetConcurrentModificationExceptionExample {
    public static void main(String[] args) {
        Set<String> fruits = new HashSet<>();

        // add example
        fruits.add("Apple");
        fruits.add("Banana");
        fruits.add("Orange");
        fruits.add("Mango");

        Iterator<String> iterator = fruits.iterator();

        while (iterator.hasNext()) {
            String fruit = iterator.next();
            System.out.println("Processing " + fruit);

            // wrong way of removing from Set, can throw java.util.ConcurrentModificationException
            if ("Orange".equals(fruit)) fruits.remove("Orange");
        }
    }
}

上面程序运行后将得到以下输出和异常

Processing Apple
Processing Mango
Processing Orange
Exception in thread "main" java.util.ConcurrentModificationException
    at java.util.HashMap$HashIterator.nextNode(HashMap.java:1442)
    at java.util.HashMap$KeyIterator.next(HashMap.java:1466)
    at HashSet.HashSetConcurrentModificationExceptionExample.main(HashSetConcurrentModificationExceptionExample.java:20)

注意!HashSet 元素不保证是有序的,调用 iterator.next() 将抛出 ConcurrentModificationException 异常。所以如果”Orange”是迭代器中的最后一个,则不会得到异常,因为 iterator.hasNext() 将返回 false,且不会调用 iterator.hasNext()

我们应该总是使用 Iterator 方法进行结构修改,如下所示:

package HashSet;

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

public class HashSetConcurrentModificationExceptionExample2 {
    public static void main(String[] args) {
        Set<String> fruits = new HashSet<>();

        fruits.add("Apple");
        fruits.add("Banana");
        fruits.add("Orange");
        fruits.add("Mango");

        Iterator<String> iterator = fruits.iterator();

        while (iterator.hasNext()) {
            String fruit = iterator.next();
            System.out.println("Processing " + fruit);

            // correct way of structural modification of Set
            if ("Orange".equals(fruit)) {
                iterator.remove();
            }
        }
        System.out.println("fruits set after iteration = " + fruits);
    }

}

上面 HashSet 迭代器栗子不会抛出异常,你会得到下面的输出:

Processing Apple
Processing Mango
Processing Orange
Processing Banana
fruits set after iteration = [Apple, Mango, Banana]

Java HashSet to Array Example

有时我们必须将 HashSet 转换为数组,反之亦然。下面是一个简单的程序,显示将 HashSet 转换为数组,然后将 Array 转换为 HashSet 的正确方法。

package HashSet;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

public class HashSetToArrayExample {
    public static void main(String[] args) {
        Set<Integer> ints = new HashSet<>();
        for (int i = 0; i < 10; i++) {
            ints.add(i);
        }
        System.out.println("ints set = " + ints);

        // set to array example
        Integer[] intArray = new Integer[ints.size()];
        intArray = ints.toArray(intArray);
        System.out.println("intArray = " + Arrays.toString(intArray));
        ints.remove(0);
        ints.remove(1);
        System.out.println("intArray = " + Arrays.toString(intArray));


        // array to set example
        ints = new HashSet<>(Arrays.asList(intArray));
        System.out.println("ints from array = " + ints);
        ints.remove(0);
        ints.remove(1);
        System.out.println("ints from array after remove = " + ints);
        System.out.println("intArray = " + Arrays.toString(intArray));
    }
}

上面 HashSet 转数组的栗子输出如下:

ints set = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
intArray = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
intArray = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
ints from array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
ints from array after remove = [2, 3, 4, 5, 6, 7, 8, 9]
intArray = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Java HashSet to List Example

Set 和 List 之间没有太大的区别,但有时候我们必须将 Set 转换为 Set 或 List 转换为 Set。面是一个简单的例子,显示了将 Set 转换为为 List,将List 设置为 Set 的正确方法。

package HashSet;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class HashSetToListExample {
    public static void main(String[] args) {
        Set<String> vowels = new HashSet<>();
        vowels.add("a");
        vowels.add("e");
        vowels.add("i");

        //set to list example
        List<String> vowelsList = new ArrayList<>(vowels);
        System.out.println("vowels set = " + vowels);
        System.out.println("vowelsList = " + vowelsList);

        vowels.add("o");
        vowelsList.add("a");
        vowelsList.add("u");
        System.out.println("vowels set = " + vowels);
        System.out.println("vowelsList = " + vowelsList);

        //list to set example
        vowels = new HashSet<>(vowelsList);
        System.out.println("vowels set = " + vowels);

    }
}

Java HashSet equals() and hashCode() methods

HashSet 利用 HashMap 来存储它的元素。当i尝试添加元素时,HashSet 用 equals()hashCode() 方法检查重复元素。让我们看看,如果你的 Set 对象没有提供 equals() 方法实现会发生什么。

package HashSet;

import java.util.HashSet;
import java.util.Set;

public class HashSetEqualsMethodImportance {
    public static void main(String[] args) {

        Set<Emp> emps = new HashSet<>();
        emps.add(new Emp(1, "Pankaj"));
        emps.add(new Emp(2, "David"));
        emps.add(new Emp(1, "Pankaj"));

        System.out.println(emps);
    }

}

class Emp {
    private String name;
    private int id;

    public Emp(int i, String n) {
        this.id = i;
        this.name = n;
    }

    @Override
    public String toString() {
        return "{" + id + "," + name + "}";
    }
}

当我们运行上面程序,我们将得到以下输出:

[{2,David}, {1,Pankaj}, {1,Pankaj}]

所以看起来我们能够在 Set 中存储重复元素。其实不是,这是因为 Emp 类没有定义 equals() 方法,因此使用了 Object 类的 equals() 方法实现。Object 类的 equals 方法定义如下:

public boolean equals(Object obj) {
        return (this == obj);
    }

所以当添加一个新元素时,对象引用被检查而不是内容。因此,我们拥有重复内容的对象,但它们具有不同的引用。让我们看看当我们在 Emp 类中定义 equals()hashCode() 方法后会发生什么。

package HashSet;

import java.util.HashSet;
import java.util.Set;

public class HashSetEqualsMethodImportance2 {
    public static void main(String[] args) {

        Set<Emp> emps = new HashSet<>();
        emps.add(new Emp(1, "Pankaj"));
        emps.add(new Emp(2, "David"));
        emps.add(new Emp(1, "Pankaj"));

        System.out.println(emps);

        Emp e = new Emp(3, "Lisa");
        emps.add(e);
        System.out.println(emps);

        //set values to make it duplicate
        e.setId(1);
        System.out.println(emps);
        e.setName("Pankaj");
        System.out.println(emps);
    }

}

class Emp {
    private String name;
    private int id;

    public Emp(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public String getName() {
        return name;
    }

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

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @Override
    public boolean equals(Object o) {
        if (o == null || !(o instanceof Emp)) return false;
        Emp emp = (Emp) o;
        if (emp.getId() == this.getId() && this.getName().equals(emp.getName())) return true;
        return false;
    }

    @Override
    public int hashCode() {

        return getId();
    }

    @Override
    public String toString() {
        return "{" + getId() + "," + getName() + "}";
    }
}

输出如下:

[{1,Pankaj}, {2,David}]
[{1,Pankaj}, {2,David}, {3,Lisa}]
[{1,Pankaj}, {2,David}, {1,Lisa}]
[{1,Pankaj}, {2,David}, {1,Pankaj}]

注意,当我们尝试添加一个元素时,HashSet 能够检查重复。但是我们可以使用 setter 方法更改对象值并使其重复。它的工作原理是因为 Set 上没有完成任何操作。这就是为什么不可变对象更适合于 Set 和 Map。

相关文章

    暂无相关文章
相关栏目:

用户点评