javaSE (二十四)关于java集合的一些的问题:为什么集合能够直接打印、HashSet到底是有序还是无序的、HashSet如何保证存储唯一?

1、为什么集合能够直接打印?

System.out.println(HashSet  has);

答:因为集合的底层重写了toString方法,调用了StringBuilder类的.append()/.toString()方法将元素拼接起来 (这个 Iterator it = iterator();什么意思???没有对象供他引用啊用这个迭代器是干嘛的??)

  public String toString() {
        Iterator<E> it = iterator();
        if (! it.hasNext())
            return "[]";

        StringBuilder sb = new StringBuilder();
        sb.append('[');
        for (;;) {
            E e = it.next();
            sb.append(e == this ? "(this Collection)" : e);
            if (! it.hasNext())
                return sb.append(']').toString();
            sb.append(',').append(' ');
        }
    }

2、HashSet到底是有序还是无序的?

先上一个代码,在HashSet存储10个范围在0到9的随机数:

package cn.njupt;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Random;

public class TTTTest {

	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static void main(String[] args) {
		
		HashSet<Integer> has = new HashSet<>();
		
		Random ran = new Random();
		
		while(has.size() != 10) {
			has.add((ran.nextInt(10)));
		}
		
		for (Integer integer : has) {
			System.out.print(integer + " ");
		}
	}

}

輸出:0 1 2 3 4 5 6 7 8 9 

很奇怪,无论编译多少次,输出是有序的????

网上看了一些回答,摘抄如下:Java遍历HashSet为什么输出是有序的?

  1. HashSet无序指的是存取无序。不是储存数据无序。
  2. 首先你要懂哈希表是什么,实质就是数组+链表,所以每插入一个对象,都会计算哈希值,插到固定位置,所以每一个对象的位置是固定的,那么hashset到底有序还是无序,答案肯定是有序的,国内的人闲麻烦就直接了当的说成无序,在国外程序员眼里这个就是有序的。
  3. 实现是会变的,HashSet的迭代器在输出时“不保证有序”,但也不是“保证无序”。也就是说,输出时有序也是允许的,但是你的程序不应该依赖这一点。

然后我用存取有序的LinkedHashSet和存取无序的HashSet来存储String对象,发现LinkedHashSet的输出和输入的顺序是一样的
HashSet的内部应该是存储有序的,就像火车上的座位号一样,虽然乘客的车票(hashcode)都不一样,但是坐下来的座位都是一样的,因为已经按照固定的位置坐了,所以出站是按照位置的,但不是和进站一样的顺序,“不保证有序”,但也不是“保证无序”

package cn.njupt;

import java.util.HashSet;
import java.util.LinkedHashSet;

public class HashSetooo {

	public static void main(String[] args) {
		// HashSet has = new HashSet<>();
		LinkedHashSet<String> has = new LinkedHashSet<>();

		has.add("z");
		has.add("x");
		has.add("a");
		has.add("a");
		has.add("a");
		has.add("e");
		has.add("f");
		has.add("d");
		has.add("f");
		has.add("b");

		System.out.println(has);

	}

}

HashSet输出:[a, b, d, e, f, x, z]   存取无序,但是取出是按照存储的顺序
LinkedHashSet输出:[z, x, a, e, f, d, b]  存取有序

3、HashSet如何保证存储唯一?
就像坐火车一样,HashSet给每一个进站的人(对象)分配了一个车票(hashcode),如果hashcode不一样,就是两个对象,如果一样,再调用该写过的equals()方法,比较对象的属性,所以如果用HashSet存储自己创建的对象(Student类等),需要重写一下hashcode()和equals()方法。
hashcode只是提供了一个调用方法的框架,方法本身还是类自己定义的,比如很多类类重写了toSting的方法,println就直接输出了println(a.toString),并不是在System里面重写toString方法

下面是自己创建的Student类重写的hashcode()和equals()方法:

@Override
public int hashCode() {
	final int prime = 31;
	int result = 1;
	result = prime * result + age;
	result = prime * result + ((name == null) ? 0 : name.hashCode());
	return result;
}

@Override
public boolean equals(Object obj) {  //写这么多,健壮性判断
	if (this == obj)                 //调用的对象和传入的对象一样
		return true;
	if (obj == null)    //传入对象为null
		return false;
	if (getClass() != obj.getClass())  //返回的字节码对象(对应的字节码文件)不是同一个
		return false;
	Student other = (Student) obj;  //向下转型
	if (age != other.age)        年龄不符合
		return false;  //年龄
	if (name == null) { //如果姓名为空
		if (other.name != null)  //姓名不为空
			return false;
	} else if (!name.equals(other.name))  //姓名不为空的时候姓名不一样
		return false;
	return true;
}

equals 属性相同返回true,不同返回false	

你可能感兴趣的:(JavaSE)