Set集合

Set及实现类

Set接口的实现类是一种只要求元素不重复,但是不关注元素的顺序的集合。

 

Set接口中的所有方法都是Collection接口中声明的方法,没有自己增加的方法。

Set集合中没有下标的概念。

 

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类的,所以所有对象都有这个方法。

 

Set集合

 

 

 如果让两个对象的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实现类的对象作为待排序对象的静态内部类,使用时从对象中获取。

两种排序方法不冲突,可以同时使用。

 

上一篇:HashSet源码


下一篇:零基础java自学流程-Java语言进阶120