Java类集-Set接口

Set接口的定义

Set接口也是Collection接口的子接口,但是与Collection或List接口不同的是,Set接口中不能加入重复的元素,其定义如下:

public interface Set<E> extends Colletion<E>

从定义上可以发现,Set接口与List接口的定义并没有太大的区别,但是Set接口的主要方法与Collection是一致的,也就是说Set接口并没有对Collection进行扩充。

Set接口的常用子类

1.散列的存放:HashSet

ContractedBlock.gif ExpandedBlockStart.gif 验证HashSet类
 
   
1 package com.yuchao.collection;
2
3   import java.util.HashSet;
4   import java.util.Set;
5
6 public class HashSetDemo {
7
8 /**
9 * @param args
10 */
11 public static void main(String[] args) {
12 // TODO Auto-generated method stub
13 Set < String > allSet = new HashSet < String > ();
14 allSet.add( " A " );
15 allSet.add( " B " );
16 allSet.add( " C " );
17 allSet.add( " C " );
18 allSet.add( " D " );
19 allSet.add( " D " );
20 allSet.add( " D " );
21 allSet.add( " E " );
22 System.out.println(allSet);
23 }
24
25 }

程序运行结果:

[D,A,C,B,E]

从程序的运行结果可以清楚地看出,对于重复元素只会增加一次,而且程序运行时向集合中加入元素的顺序并不是集合中的保存顺序,证明HashSet类中的元素是无序排列的。

2.有序的存放:TreeSet

ContractedBlock.gif ExpandedBlockStart.gif 验证TreeSet类
 
   
1 package com.yuchao.collection;
2
3 import java.util.HashSet;
4 import java.util.Set;
5
6 public class HashSetDemo {
7
8 /**
9 * @param args
10 */
11 public static void main(String[] args) {
12 // TODO Auto-generated method stub
13 Set < String > allSet = new HashSet < String > ();
14 allSet.add( " A " );
15 allSet.add( " B " );
16 allSet.add( " C " );
17 allSet.add( " C " );
18 allSet.add( " D " );
19 allSet.add( " D " );
20 allSet.add( " D " );
21 allSet.add( " E " );
22 System.out.println(allSet);
23 }
24
25 }

程序运行结果:

[A,B,C,D,E]

程序在向集合中插入数据时是没有顺序的,但是输出之类数据是有序的,所以TreeSet是可以排序的。

3.关于TreeSet的一些思考

既然TreeSet本身是可以排序的,那么自定义的一个类,是否也可以随意进行排序呢?

ContractedBlock.gif ExpandedBlockStart.gif 自定义类排序
 
   
1 package com.yuchao.collection;
2
3 import java.util.Set;
4 import java.util.TreeSet;
5
6 public class TreeSetDemo {
7
8 /**
9 * @param args
10 */
11 public static void main(String[] args) {
12 // TODO Auto-generated method stub
13 Set < Person > allSet = new TreeSet < Person > ();
14 allSet.add( new Person( " 张三 " , 30 ));
15 allSet.add( new Person( " 李四 " , 31 ));
16 allSet.add( new Person( " 王五 " , 32 ));
17 allSet.add( new Person( " 王五 " , 32 ));
18 allSet.add( new Person( " 王五 " , 32 ));
19 allSet.add( new Person( " 赵六 " , 33 ));
20 allSet.add( new Person( " 孙七 " , 33 ));
21 System.out.println(allSet);
22
23 }
24
25 }
26
27 class Person
28 {
29 private String name;
30 private int age;
31 public Person(String name, int age)
32 {
33 this .name = name;
34 this .age = age;
35 }
36
37 public String toString()
38 {
39 return " 姓名: " + this .name + " ; " + " 年龄: " + this .age;
40 }
41 }

程序运行时出现以下错误:

Exception in thread "main" java.lang.ClassCastException: com.yuchao.collection.Person cannot be cast to java.lang.Comparable
    at java.util.TreeMap.put(TreeMap.java:542)
    at java.util.TreeSet.add(TreeSet.java:238)
    at com.yuchao.collection.TreeSetDemo.main(TreeSetDemo.java:15)

以下程序代码出现了类转换异常,会出现这样的问题,是因为TreeSet中的元素是有序存放,所以对一个对象必须指定好其排序规则,且TreeSet中每个对象所在的类都必须实现Comparable接口才可以正常使用。

ContractedBlock.gif ExpandedBlockStart.gif 指定排序规则的自定义类排序
 
   
1 package com.yuchao.collection;
2
3 import java.util.Set;
4 import java.util.TreeSet;
5
6 public class TreeSetDemo {
7
8 /**
9 * @param args
10 */
11 public static void main(String[] args) {
12 // TODO Auto-generated method stub
13 Set < Person > allSet = new TreeSet < Person > ();
14 allSet.add( new Person( " 张三 " , 30 ));
15 allSet.add( new Person( " 李四 " , 31 ));
16 allSet.add( new Person( " 王五 " , 32 ));
17 allSet.add( new Person( " 王五 " , 32 ));
18 allSet.add( new Person( " 王五 " , 32 ));
19 allSet.add( new Person( " 赵六 " , 33 ));
20 allSet.add( new Person( " 孙七 " , 33 ));
21 System.out.println(allSet);
22 }
23
24 }
25
26 class Person implements Comparable < Person >
27 {
28 private String name;
29 private int age;
30 public Person(String name, int age)
31 {
32 this .name = name;
33 this .age = age;
34 }
35
36 public String toString()
37 {
38 return " 姓名: " + this .name + " ; " + " 年龄: " + this .age;
39 }
40
41 public int compareTo(Person person)
42 {
43 if ( this .age > person.age)
44 {
45 return 1 ;
46 } else if ( this .age < person.age){
47 return - 1 ;
48 } else {
49 return 0 ;
50 }
51 }
52 }

程序运行结果:

[姓名:张三;年龄:30, 姓名:李四;年龄:31, 姓名:王五;年龄:32, 姓名:赵六;年龄:33]

从程序的运行结果中可以发现,重复的”王五“对象只有一个;”赵六“和”孙七“年龄重复,但是”孙七“并没有加入到集合中。这是由于采用了比较器造成的,因为比较器操作时如果某个属性没有进行比较的指定,则也会认为是同一个对象,所以此时应该在Person类的compareTo方法中增加按姓名比较。

ContractedBlock.gif ExpandedBlockStart.gif 修改Person比较器
 
   
package com.yuchao.collection;

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

public class TreeSetDemo {

/**
*
@param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Set < Person > allSet = new TreeSet < Person > ();
allSet.add(
new Person( " 张三 " , 30 ));
allSet.add(
new Person( " 李四 " , 31 ));
allSet.add(
new Person( " 王五 " , 32 ));
allSet.add(
new Person( " 王五 " , 32 ));
allSet.add(
new Person( " 王五 " , 32 ));
allSet.add(
new Person( " 赵六 " , 33 ));
allSet.add(
new Person( " 孙七 " , 33 ));
System.out.println(allSet);
}

}

class Person implements Comparable < Person >
{
private String name;
private int age;
public Person(String name, int age)
{
this .name = name;
this .age = age;
}

public String toString()
{
return " 姓名: " + this .name + " ; " + " 年龄: " + this .age;
}

public int compareTo(Person person)
{
if ( this .age > person.age)
{
return 1 ;
}
else if ( this .age < person.age){
return - 1 ;
}
else {
return this .name.compareTo(person.name);
}
}
}

程序输出结果:

[姓名:张三;年龄:30, 姓名:李四;年龄:31, 姓名:王五;年龄:32, 姓名:孙七;年龄:33, 姓名:赵六;年龄:33]

以下程序运行结果出现了”孙七",而且去掉了重复的内容,但此时的重复内容去掉,并不是真正意义上的去掉重复元素。因为此时靠的是Comparable接口完成的,而如果换成HashSet则也会出现重复的内容,所以要想真正的去掉重复元素,则必须深入研究Object类。

提示:想要判断对象是否重复必须覆盖Object类中的equals()方法,但同时必须覆盖hashCode()方法,此方法表示一个哈希编码,一般哈希码是通过公式进行计算的,可以将类的全部属性进行适当计算,以求出一个不会重复的哈希码。

ContractedBlock.gif ExpandedBlockStart.gif 修改equals()、hashCode()去除重复元素
 
   
package com.yuchao.collection;

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

public class TreeSetDemo {

/**
*
@param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
// Set<Person> allSet=new TreeSet<Person>();
Set < Person > allSet = new HashSet < Person > ();
allSet.add(
new Person( " 张三 " , 30 ));
allSet.add(
new Person( " 李四 " , 31 ));
allSet.add(
new Person( " 王五 " , 32 ));
allSet.add(
new Person( " 王五 " , 32 ));
allSet.add(
new Person( " 王五 " , 32 ));
allSet.add(
new Person( " 赵六 " , 33 ));
allSet.add(
new Person( " 孙七 " , 33 ));
System.out.println(allSet);
}

}

class Person
{
private String name;
private int age;
public Person(String name, int age)
{
this .name = name;
this .age = age;
}

public String toString()
{
return " 姓名: " + this .name + " ; " + " 年龄: " + this .age;
}

public boolean equals(Object object)
{
if ( this == object)
{
return true ;
}
if ( ! (object instanceof Person))
{
return false ;
}
Person person
= (Person)object;
if ( this .name.equals(person.name) && this .age == person.age)
{
return true ;
}
else
{
return false ;
}
}

public int hashCode()
{
return this .name.hashCode() * this .age;
}

}
提示:在实际开发中经常会碰到区别同一对象的问题,所以,一个完整的类最好覆写Object类的hashCode()、equals()、toString()3个方法。

转载于:https://www.cnblogs.com/yuchao/archive/2011/02/26/1965714.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值