您的位置:首页 > 编程语言 > Java开发

Java集合框架总结之Set接口的使用

2015-11-09 10:16 561 查看
List接口和Set接口都继承自Collection接口,区别如下:

List中的元素有序,且可以重复,元素可以用下标操作

Set中的元素无序,且不能重复,元素无法用下标操作

下面我们仅仅介绍Set接口的使用,List接口的使用请参考:

http://blog.csdn.net/u011983531/article/details/49735115

一、Set接口的常见操作

因为我们经常使用Set接口来操作它的实现类(如:HashSet)的对象,所以对Set接口中常见的操作,一定要非常熟悉。

注:Set中的元素无法用下标操作

(1)添加

//如果set 中尚未存在指定的元素,则添加此元素
boolean add(E e)
//如果set 中没有指定collection 中的所有元素,则将其添加到此set 中
boolean addAll(Collection<? extends E> c)


(2)删除

//移除此 set 中的所有元素
void clear()
//如果 set 中存在指定的元素,则将其移除
boolean remove(Object o)
//移除 set 中那些包含在指定 collection 中的元素
boolean removeAll(Collection<?> c)


(3)查找

//返回在此 set 中的元素上进行迭代的迭代器
Iterator<E> iterator()


(4)其他操作

//返回set中的元素数
int size()
//判断set是否为空,如果set不包含元素,则返回 true
boolean isEmpty()
//判断集合中是否包含指定的元素
boolean contains(Object o)
//如果此 set 包含指定 collection 的所有元素,则返回 true
boolean containsAll(Collection<?> c)
//返回一个包含set中所有元素的数组
Object[] toArray()


注意:由于Set中的元素是不重复的,所以在添加元素时,需要判断Set中是否有该元素。下面的HashSet的TreeSet详细介绍了如何保证Set中的元素不重复。

二、Set接口常见子类

HashSet:内部数据结构是哈希表,是线程不安全的。

TreeSet:内部数据结构是二叉排序树,是线程不安全的。

1、HashSet

HashSet的内部数据结构是哈希表,下面是哈希表确定元素是否相同的方法:

首先判断的是两个对象的哈希值是否相同,如果相同,再判断两个对象的内容是否相同。

注:判断哈希值是否相同,其实是判断对象的hashCode()方法的返回结果是否相同;判断内容是否相同,用的是对象的equals()方法。如果哈希值不相同,不需要判断equals()方法。

所以,在使用HashSet存储对象时,必须实现对象的hashCode()方法和equals()方法。

举例说明:

package com.ghs.test;

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

public class TestHashSet {

public static void main(String[] args) {
Set<Person> persons = new HashSet<Person>();
persons.add(new Person("zhangsan", 21));
persons.add(new Person("lisi", 21));
persons.add(new Person("zhangsan", 21));
persons.add(new Person("wangwu", 21));

System.out.println(persons.size());
}
}

class Person{
private String name;
private int age;

public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
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;
}
//当name和age都相同时,表示是同一个人
@Override
public int hashCode() {
return this.name.hashCode() + age*31;
}

@Override
public boolean equals(Object obj) {
if( this ==obj)
return true ;
if(!(obj instanceof Person) )
throw new ClassCastException();
Person person = (Person) obj;
return this.name.equals(person.getName()) && this.age==person.getAge();
}
}


如果Person类没有重写hashCode()和equals()方法,或者只重写了其中一个,[zhangsan,21]这条记录都会被添加两次。

2、TreeSet

TreeSet判断元素是否相同的方法:

根据比较方法的返回结果来判断,如果是0,就是相同元素,不存储,否则就是不同元素。

所以,在使用TreeSet存储对象时,要么对象实现Comparable接口,要么定义在创建TreeSet时,传入比较器。

(1)实现Comparable举例:

package com.ghs.test;

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

public class TestTreeSet {

public static void main(String[] args) {
Set<Person> persons = new TreeSet<Person>();
persons.add(new Person("zhangsan", 21));
persons.add(new Person("lisi", 21));
persons.add(new Person("zhangsan", 21));
persons.add(new Person("wangwu", 21));

System.out.println(persons.size());
}
}

class Person implements Comparable{
private String name;
private int age;

public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
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 int compareTo(Object obj) {
if(!(obj instanceof Person) )
throw new ClassCastException();
Person person = (Person) obj;
int temp = this.name.compareTo(person.getName());
return temp ==0 ? this.age-person.getAge() :temp ;
}
}


如果Person类没有实现Comparable接口,运行过程中就会出现类型转换异常。

(2)使用比较器举例

package com.ghs.test;

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

public class TestTreeSet2 {
public static void main(String[] args) {
Set<Person> persons = new TreeSet<Person>(new PersonComparator());
persons.add(new Person2("zhangsan", 21));
persons.add(new Person2("lisi", 21));
persons.add(new Person2("zhangsan", 21));
persons.add(new Person2("wangwu", 21));

System.out.println(persons.size());
}
}

class Person{
private String name;
private int age;

public Person2(String name, int age) {
super();
this.name = name;
this.age = age;
}
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;
}
}

class PersonComparator implements Comparator{

@Override
public int compare(Object obj1, Object obj2) {
if(!(obj1 instanceof Person) )
throw new ClassCastException();
if(!(obj2 instanceof Person) )
throw new ClassCastException();
Person person1 = (Person) obj1;
Person person2 = (Person) obj2;
int temp = person1.getName().compareTo( person2.getName()) ;
return temp == 0 ? person1.getAge()-person2.getAge():temp ;
}
}


三、遍历Set中的元素

遍历Set中的元素有两种方法,一种是使用迭代器,另一种是直接使用增强for循环,但是不能用下标操作。

//遍历
public static void testSet(){
HashSet<Person> persons = new HashSet<Person>();
persons.add(new Person("zhangsan", 21));
persons.add(new Person("lisi", 21));
persons.add(new Person("wangwu", 21));

//方法一:迭代器
Iterator<Person> it = persons.iterator();
for(Person p = it.next() ; it.hasNext();){
System.out.println(p.getName() +"----"+p.getAge());
}
//或者
while(it.hasNext()){
Person p = (Person) it.next() ;
System.out.println(p.getName() +"----"+p.getAge());
}
//方法二:for循环
for(Person p : persons){
System.out.println(p.getName() +"----"+p.getAge());
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息