• Java基础教程——Set


    Set·无序,不重复

    HashSet

    特点:没有重复数据,数据不按存入的顺序输出。

    HashSet由Hash表结构支持。不支持set的迭代顺序,不保证顺序。
    但是Hash表结构查询速度很快。

    创建集合使用代码:

    Set<String> s = new HashSet<>();
    

    代码演示:常用方法和遍历输出

    import java.util.*;
    public class TestHashSet {
    	public static void main(String[] args) {
    		m010赋值And遍历();
    	}
    	public static void m010赋值And遍历() {
    		System.out.println("=====赋值And遍历");
    		Set<String> s = new HashSet<>();
    		s.add("孙悟空");
    		s.add("小白龙");
    		s.add("猪八戒");
    		s.add("沙悟净");
    		s.add("孙悟空");
    		System.out.println("是否为空:" + s.isEmpty());
    		System.out.println("是否包含:" + s.contains("小白龙"));
    		System.out.println("移除:" + s.remove("小白龙"));
    		// (1)foreach:遍历set
    		for (String str : s) {
    			System.out.println(str);
    		}
    		// (2)迭代器:遍历set
    		Iterator<String> it = s.iterator();
    		while (it.hasNext()) {
    			String str = it.next();
    			System.out.println("Iterator : " + str);
    		}
    		// (3)*Java 8新增遍历方法
    		s.forEach(elm -> System.out.println("Lambda:" + elm));
    	}
    }
    

    Hash和Hash表

    Hash

    HashCode,是一个十进制整数,是对象的地址值(逻辑地址,不是物理地址)
    Object类有一个方法,可以获取对象的Hash值。

    public native int hashCode();
    

    String重写了hashCode方法

        public int hashCode() {
            int h = hash;
            if (h == 0 && value.length > 0) {
                char val[] = value;
    
                for (int i = 0; i < value.length; i++) {
                    h = 31 * h + val[i];
                }
                hash = h;
            }
            return h;
        }
    

    以至于有些不同字符串的hashCode相等(字符串还是不等的,无论==还是equals):

    		System.out.println("重地".hashCode());
    		System.out.println("通话".hashCode());
    		System.out.println("--------------");
    		System.out.println("方面".hashCode());
    		System.out.println("树人".hashCode());
    		System.out.println("--------------");
    		System.out.println("儿女".hashCode());
    		System.out.println("农丰".hashCode());
    		System.out.println("--------------");
    		System.out.println("Ea".hashCode());
    		System.out.println("FB".hashCode());
    

    Hash表

    Java8之前:Hash表使用数组+链表;
    Java8之后加入了红黑树,查询速度加快。

    Hash表结构的示意图如下所示:

    数组里存储的是HashCode。
    HashCode相同的元素加入相同链表;
    如果链表长度超过8,就转为红黑树以提高查询速度。

    怎么才算重复?

    HashSet中,元素不重复指“equals方法比较为true,且hashCode不同”。

    下列示例代码中,只有equals为true、且hashCode相同的对象未重复存入Set中。

    import java.util.*;
    class A_equalsT {
    	public boolean equals(Object obj) {
    		return true;
    	}
    }
    class B_hash1 {
    	public int hashCode() {
    		return 1;
    	}
    }
    class C_hash2_equalsT {
    	public int hashCode() {
    		return 2;
    	}
    	public boolean equals(Object obj) {
    		return true;
    	}
    }
    public class TestSet怎么才算重复 {
    	public static void main(String[] args) {
    		Set<Object> _set = new HashSet<Object>();
    		_set.add(new A_equalsT());
    		_set.add(new A_equalsT());
    		_set.add(new B_hash1());
    		_set.add(new B_hash1());
    		_set.add(new C_hash2_equalsT());
    		_set.add(new C_hash2_equalsT());
    		for (Object object : _set) {
    			System.out.println(object);
    		}
    	}
    }
    

    运行结果:(C_hash2_equalsT只存入一份,说明被看作重复对象)

    B_hash1@1
    B_hash1@1
    C_hash2_equalsT@2
    A_equalsT@15db9742
    A_equalsT@6d06d69c
    

    HashSet存储自定义元素时,需要重写hashCode和equals方法,才能保证集合中对象的唯一性。

    练习:

    创建Student类,至少需要包含id、name。创建多个Student对象加入HashSet,如果学号(id)相同则不重复加入。

    TreeSet

    TreeSet支持两种排序方式,自然排序和定制排序。默认为自然排序,和HashSet的输出顺序不一样。

    TreeSet使用红黑树存储元素(示例和下一小节一起)。

    LinkedHashSet

    Set也可以有序,这个LinkedHashSet就能按照输入顺序输出结果。

    LinkedHashSet也是根据元素的hashCode值决定元素的存储位置,但是加了一条链表记录元素的存储顺序,这使得元素有序。

    import java.util.HashSet;
    import java.util.LinkedHashSet;
    import java.util.Set;
    import java.util.TreeSet;
    public class TestTree{
    	public static void main(String[] args) {
    		m020各种Set();
    	}
    	private static void m020各种Set() {
    		System.out.println("|-HashSet:");
    		Set<String> _set;
    		_set = new HashSet<String>();
    		_set.add("B");
    		_set.add("A");
    		_set.add("1");
    		_set.add("2");
    		_set.add(null);
    		printSet(_set);
    		System.out.println("|-TreeSet不接受空值:");
    		_set = new TreeSet<String>();
    		_set.add("B");
    		_set.add("A");
    		_set.add("1");
    		_set.add("2");
    		// _set.add(null);
    		printSet(_set);
    		System.out.println("|-LinkedHashSet:有序");
    		_set = new LinkedHashSet<String>();
    		_set.add("B");
    		_set.add("A");
    		_set.add("1");
    		_set.add("2");
    		_set.add(null);
    		printSet(_set);
    	}
    	private static void printSet(Set<String> _set) {
    		for (String str : _set) {
    			System.out.print(str + " ");
    		}
    		System.out.println();
    	}
    }
    

    |-HashSet:
    null A 1 B 2
    |-TreeSet不接受空值:
    1 2 A B
    |-LinkedHashSet:有序
    B A 1 2 null

    Set的性能

    HashSet综合效率最高,LinkedHashSet因为有链表,遍历时会更快一些。TreeSet因为要维护红黑树,效率较低。

  • 相关阅读:
    推荐一个博客,或许给技术流的自己一些启示
    Boost多线程-替换MFC线程
    Python:Matplotlib 画曲线和柱状图(Code)
    AI:机器人与关键技术--总是被科普
    OnLineML一:关于Jubatus 的简介...
    使用PCL::GPU::遇到问题
    dll文件:关于MFC程序不能定位输入点
    实践:使用FLANN.LSH进行检索
    模式识别两种方法:知识和数据
    几个方便编程的C++特性
  • 原文地址:https://www.cnblogs.com/tigerlion/p/11179209.html
Copyright © 2020-2023  润新知