zoukankan      html  css  js  c++  java
  • 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因为要维护红黑树,效率较低。

  • 相关阅读:
    C#、Java实现按字节截取字符串包含中文汉字和英文字符数字标点符号等
    百度编辑器(UEditor)自定义工具栏
    ASP.NET使用百度编辑器(UEditor)使用方法
    C#设计模式--桥接模式
    C#设计模式--外观模式
    Entity Framework6测试使用
    Entity Framework6的在线下载安装
    C#设计模式--代理模式
    php 回调函数结合闭包(匿名函数)的使用示例
    函数的可变参数实例
  • 原文地址:https://www.cnblogs.com/tigerlion/p/11179209.html
Copyright © 2011-2022 走看看