Set及实现类
Set接口的实现类是一种只要求元素不重复,但是不关注元素的顺序的集合。
Set接口中的所有方法都是Collection接口中声明的方法,没有自己增加的方法。
Set集合中没有下标的概念。
Set接口的实现类:
HashSet:使用数组实现,元素的顺序和放入的顺序无关
LinkedHashSet:使用链表实现,元素的顺序和放入的顺序一致
TreeSet:可以对元素进行排序的Set集合
使用Set类型的引用,只关心共性,不关心每个实现类的细节。
Set set = new HashSet( ); set.add( "张三" ); set.add( "李四" ); set.add( "王五" ); set.add( "张三" ); System.out.println( set ); //顺序可能不一致 没有相同元素
Set set = new LinkedHashSet( ); set.add( "张三" ); set.add( "李四" ); set.add( "王五" ); set.add( "张三" ); System.out.println( set ); //顺序一致 //没有相同元素
HashSet能够保证放入的字符串不重复。
如果放入自定义类型的对象,也能保证不重复吗?
Set set = new HashSet( ); set.add( new Student("张三", 20) ); set.add( new Student("张三", 20) ); System.out.println( set );
两次放入的Student对象虽然属性完全相同,但是它们是使用了两次构造方法创建的两个不同的对象,它们在内存中处于不同的位置,所以HashSet不会把这两个对象视为重复对象。
思考:
如何让HashSet将属性完全相同的对象视为重复对象?
让Student类覆盖equals( )方法,让HashSet能够判断两个对象是否重复。
HashSet能够根据equals( )方法判断两个对象是否为重复对象吗?
能,但是还需要实现一个另外的方法。
将一个对象放入HashSet集合时,HashSet集合会先调用对象的hashCode( )方法,拿到对象的hashcode值。
对象一定有hashcode()方法吗?
是的,hashCode( )方法是Object类的,所以所有对象都有这个方法。
如果让两个对象的hashcode相同,就可以在放入HashSet时调用equals( )方法判断是否为重复对象。
public int hashCode( ) { return 0; } //覆盖hashCode( )方法,返回相同的值
覆盖hashCode( )方法,让同一个类的所有对象返回相同的值,同时覆盖equals( )方法,可以保证在放入HashSet时排除重复的元素。
问题:属性不同的元素的hashcode值也相同,也使用equals( )方法比较,会影响效率,如何改进?
改进:相同元素的hashcode值相同,不同元素的hashcode值尽量不同。可以根据对象的属性计算hashcode值。
总结: 把自定义的对象放入HashSet或LinkedHashSet,为保证元素内容不重复,需要:
覆盖hashCode( )方法,保证相同对象返回相同的值,提供调用equals( )方法的机会。
覆盖equals( )方法,相同对象返回true。
Set set = new TreeSet( ); set.add( "张三" ); set.add( "李四" ); set.add( "王五" ); set.add( "张三" ); System.out.println( set ); //按照字符排序 //没有相同元素
TreeSet能够自动给放入的String对象排序。
如果放入自定义类型的对象,也能排序吗?
Set set = new TreeSet( ); set.add( new Student("张三", 20) ); set.add( new Student("张三", 20) ); System.out.println( set ); //运行失败 //为什么?
TreeSet是能够给元素排序的Set集合,要给元素排序,必须提供排序规则。
提供排序规则的方式:
元素所属的类实现Comparable接口
使用实现了Comparator接口的对象创建TreeSet对象
class Student implements Comparable { …… public int compareTo( Object obj ) { …… } }
如果一个对象所属的类实现了Comparable接口,则可以直接把这些对象放入TreeSet集合中,TreeSet集合会自动调用对象的compareTo( )方法,根据返回的结果进行排序:
负数:this对象排在obj对象之前
正数:this对象排在obj对象之后
0:视为重复对象
如果希望可以对某一类对象按照多个规则进行不同的排序,可以使用Comparator实现类的对象创建TreeSet集合:
Set set = new TreeSet ( new Comparator( ) { public int compare( Object o1, Object o2 ) { return ( ( Student ) o1 ).getAge( ) - ( ( Student ) o2 ).getAge( ); } } ); //要创建匿名内部类
使用Comparator实现类的对象创建的TreeSet集合不会使用对象的compareTo( )方法排序,所以不要求对象所属的类必须实现Comparable接口。TreeSet集合根据compare( )方法返回的结果进行排序:
负数:o1对象排在o2对象之前
正数:o1对象排在o2对象之后
0:视为重复对象
两种排序方式比较:
使用Comparable只能对对象按照一个规则排序,使用Comparator可以对对象按照多个规则排序,更加灵活。
可以把多个Comparator实现类的对象作为待排序对象的静态内部类,使用时从对象中获取。
两种排序方法不冲突,可以同时使用。