Java总结_百宝袋集合类(3)Set

1、Set接口

  Set是无序不可重复的集合接口,从JDK中可以看到Set继承了Collection接口中的方法,其自身并没有额外添加实质性方法,只是在原有的Collection方法基础上,重申了方法注释,以区别于父类的使用,它的实现类常用的有HashSet和TreeSet,下面分别介绍这两个类的区别和使用;

2、HashSet
2.1HashSet的特征

(1) 继承了AbstractSet,并实现了Set、Cloneable、Serializable接口;
(2) 采用散列表HashMap实现无序不可重复的特性;

  • 无序,输入顺序不等于输出顺序;
public static void main(String[] args) {
		Set<String> set=new HashSet<String>();
		set.add("A");
		set.add("C");
		set.add("B");
		System.out.println(set);//输出顺序[A,B,C]
	}
  • 不可重复,基于equals方法判断元素是否相等,由于equals和hashCode都是成对出现且具有一致性(要么都相等,要么都不相等);

定义Person类

package xw.zx.model;

public class Person {
	private int id;
	private String name;
	private int age;
	public Person(int id, String name,int age) {
		super();
		this.id = id;
		this.name = name;
		this.age=age;
	}
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	@Override
	public String toString() {
		return "Person [id=" + id + ", name=" + name + ", age=" + age + "]";
	}
	
	
	
	
}

测试不可重复性

package xw.zx.collection;

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

import xw.zx.model.Person;

public class SetDemo {
	

	public static void main(String[] args) {
		Set<String> set=new HashSet<String>();
		/**
		 * 字符串如果采用字面量赋值,那么将会以常量池的方式存储
		 * 注: s1="A",s2="A";那么 s1==s2 返回值为true;
		 */
		String s1=new String("A");
		String s2=new String("A");
		String s3=new String("B");
		System.out.println(s1==s2);//false
		//字符串对象重写了equals方法
		System.out.println(s1.equals(s2));//true
		set.add(s1);
		set.add(s2);
		set.add(s3);
		
		
		System.out.println(set);
		Set<Person> set1=new HashSet<Person>();
		//自定义的Person类,未重写equals方法
		Person p1=new Person(1,"张三",16);
		Person p2=new Person(1,"张三",16);
		Person p3=new Person(2,"李四",25);
		set1.add(p1);
		set1.add(p2);
		set1.add(p3);	
		System.out.println(p1==p2);//false
		System.out.println(p1.equals(p2));//false
		System.out.println(set1);
		
	}
	
}


输出结果:
在这里插入图片描述
  从输出的结果中可以看出字符串没有重复输出“A” ,但是自定义的类“Person”却存在重复现象,通过查看JDK8发现String类对equals和hashCode方法进行了重写,而我们的自定义的类并未重写equals和hashCode方法,始终调用Object中默认的方法;
  String类中的equals和hashCode方法

 public boolean equals(Object anObject) {
 		//判断是否为同一引用
        if (this == anObject) {
            return true;
        }
        //判断是否为字符串,才具有可比性;
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            //判断字节数组是否相等
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }
    /**
    *采用s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]形式构建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;
    }

  《Java编程思想》中提到正确的equals方法必须满足以下条件:
1、 自反性。对任意x,x.equals(x)一定返回true;
2、 对称性。对任意x和y,如果y.equals(x)返回true,则x.equals(y)也返回true;
3、 传递性。对任意的x、y、z,如果x.equals(y)返回true,y.equals(z)返回true,那么x.equals(z)也一定返回true;
4、 一致性。对任意的x和y,如果对象中用于等价比较的信息没有改变,那么无论条用x.equals(y)多少次,返回的结果应该保持一致,要么一直是true,要么一直是false;
5、 对任意不是null的x,x.equals(null)一定返回false;
  而设计hashCode()时最重要的因素就是:无论何时,对同一个对象调用hashCode()都应该生成同样的值。所以hashCode码应该由类中不易变的成员变量生成;
Person类中重写equals和hashCode()方法

@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
	   //age是易变的成员变量,不能用来定义hashCode码
		//result = prime * result + age;
		result = prime * result + id;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}
	/**
	 * 模仿String的equals方法,重写Person的equals的方法满足5大条件
	 */
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;		
		if(obj instanceof Person) {
			return id==((Person)obj).getId() && name.equals(((Person) obj).getName());
		}
		return false;
	}

这样,重新编译后输出的结果如下:
在这里插入图片描述
(3) 由于采用了哈希无序存储,所以集合的遍历不能基于索引的For循环,而应该使用Interator迭代器遍历或者forEach语法;

package xw.zx.collection;

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

import xw.zx.model.Person;

public class SetDemo {
	

	public static void main(String[] args) {
	
		Set<Person> set1=new HashSet<Person>();
		Person p1=new Person(1,"张三",16);
		Person p2=new Person(1,"张三",16);
		Person p3=new Person(2,"李四",25);
		set1.add(p1);
		set1.add(p2);
		set1.add(p3);	
		//基于迭代Iterator
	    Iterator<Person> i=set1.iterator(); 
	    while(i.hasNext()) {
		    System.out.println(i.next().getName()); 
	    } 
	    //基于forEach
	    for(Person p :set1) {
		    System.out.println(p.getName()); 
	    }	   
		 
	}
	
}
3、TreeSet
3.1、TreeSet特征

(1)基于TreeMap采用红黑数结构存储数据;

  public TreeSet() {
        this(new TreeMap<E,Object>());
    }

(2)要求用于存储的对象必须要实现Comparable方法,否则会报错ClassCastException;

package xw.zx.collection;

import java.util.Set;
import java.util.TreeSet;

import xw.zx.model.Person;

public class SetDemo02 {
	public static void main(String[] args) {
		Set<Person> set=new TreeSet<Person>();
		Person p1=new Person(1,"张三",16);
		Person p2=new Person(1,"张三",16);
		Person p3=new Person(2,"李四",25);
		Person p4=new Person(3,"王五",26);
		set.add(p1);
		set.add(p2);
		set.add(p3);
		set.add(p4);
		System.out.println(set);
	}
	
}

  输出后提示Person无法转化为Comparable;
在这里插入图片描述
  所以应该让Person类实现Comparable接口,并重写compareTo方法

@Override
	public int compareTo(Object o) {
		return id-((Person)o).getId();
	}

重新编译后输出结果:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值