黑马程序员——Java学习日志之Set集合

}<span style="font-family: Simsun; background-color: rgb(255, 255, 255);">------- </span><a target=_blank href="http://www.itheima.com/" target="blank" style="font-family: Simsun; background-color: rgb(255, 255, 255);">android培训</a><span style="font-family: Simsun; background-color: rgb(255, 255, 255);">、</span><a target=_blank href="http://www.itheima.com/" target="blank" style="font-family: Simsun; background-color: rgb(255, 255, 255);">java培训</a><span style="font-family: Simsun; background-color: rgb(255, 255, 255);">、期待与您交流! ----------</span>

今天的学习内容是集合的Set结构

相比于Link结构,Set的特点是无序(存储和读取的顺序是不一致的),无索引,不可以重复存储相同元素。

Ste集合的这个帮派中,有HashSet和TreeSet两大马仔。两个各司其职,各有擅长的地方。

 

类 hashSet<.E>

       这个类的特点是:

不保证迭代顺序;

也不保证顺序不变(上次输出结果和下次输出结果未必一样,即使没有对容器进行任何操作和修改);

但是能够保证元素不重复。(这恐怕就是hashSet的看家本领了)

 

hashSet这个唯一赖以生存的本领的实现原理是什么呢?

首先就是写在的名字上的hash。

1.HashSet原理

       *我们使用Set集合都是需要去掉重复元素的, 如果在存储的时候逐个equals()比较, 效率较低,哈希算法提高了去重复的效率,降低了使用equals()方法的次数

       *当HashSet调用add()方法存储对象的时候, 先调用对象的hashCode()方法得到一个哈希值, 然后在集合中查找是否有哈希值相同的对象

              *如果没有哈希值相同的对象就直接存入集合

              *如果有哈希值相同的对象, 就和哈希值相同的对象逐个进行equals()比较,比较结果为false就存入, true则不存

 2.将自定义类的对象存入HashSet去重复

        类中必须重写hashCode()和equals()方法

      

hashCode(): 属性相同的对象返回值必须相同, 属性不同的返回值尽量不同(提高效率)

        equals(): 属性相同返回true, 属性不同返

在向集合中添加元素时,内在的逻辑是先比较元素的hashCode,当hashCode一样时,再用equals方法比较。

Hashcode是方法hashCode()生成的很有可能是元素独有的标识。

@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;
	}

PS:这里的prime的值为何是31?一方面是因为它是个不大不小的指数,这样算出来的hashCode更容易独一无二。另一方面,31是2^5-1,系统得到这个数比较快。

@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Person other = (Person) 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;
	}

Tips:eclipse中,在自定义类中,shift + Alt + s 再按h ,可以自动生成hashCode和equals方法

LinkedHashSet

特点: 可以保证怎么存就怎么取

在操作上,LinkedHashSet没什么特殊之处。和其他集合的操作相同。

 

TreeSet

       首先,TreeSet是一个用来对元素排序的的集合。这个功能很强大,以后就不用自己写那麻烦的双循环嵌套的排序算法了。

自定义类必须实现Comparable接口,才能成功被添加进TreeSet集合中。

实现Comparable接口就要重写CompareTo方法。当对象被添加进集合中时,集合会调用该对象的CompareTo方法和集合内的元素进行比较。

CompateTo 会返回一个int类型。

TreeSet的数据结构是二叉树。每个节点都有两个引用,分别指向下一级的左节点、右节点。

CompareTo的返回值是负数时,新元素存数在左边;是正数时,存放在右边;等于0时不存储。

读取的顺序是左中右。这样就实现了对元素的排序。

 

当然,自定义类的CompareTo你也可以重写,按实际要求做出修改。例如当要求允许重复元素时,就要把返回值0的情况归到不为零的判断中。

 

TreeSet的比较器排序。

       比较器需要自己定义。因为只是在实例化TreeSet时才调用一次比较器,所以可以用匿名内部类的方式来定义。

例如:

<p>TreeSet<String> ts = newTreeSet<>(new Comparator<String>() {          //定义比较器(new<span style="font-family: Arial, Helvetica, sans-serif;">Comparator(){}是Comparator的子类对象)</span></p><p><span style="white-space: pre;">	</span>@Override</p><p>     publicint compare(String s1, String s2) {               //重写compare方法</p><p>     intnum = s1.compareTo(s2);                       //比较内容</p><p>     returnnum == 0 ? 1 : num;                       //如果内容一样返回一个不为0的数字即可</p><p>    }</p><p>});</p>

两种排序方式的总结:

       *a.自然顺序(Comparable)

              *TreeSet类的add()方法中会把存入的对象提升为Comparable类型

              *调用对象的compareTo()方法和集合中的对象比较

              *根据compareTo()方法返回的结果进行存储

       *b.比较器顺序(Comparator)

              *创建TreeSet的时候可以制定 一个Comparator

              *如果传入了Comparator的子类对象, 那么TreeSet就会按照比较器中的顺序排序

              *add()方法内部会自动调用Comparator接口中compare()方法排序

              *调用的对象是compare方法的第一个参数,集合中的对象是compare方法的第二个参数

       *c.两种方式的区别

              *TreeSet构造函数什么都不传, 默认按照类中Comparable的顺序(没有就报错ClassCastException)

              *TreeSet如果传入Comparator,就优先按照Comparator



你可能感兴趣的:(黑马程序员——Java学习日志之Set集合)