JAVA集合类型显示化_java 集合类 之 Set

Set类

Set接口继承自Collection,不按特定的方式排序,并且不能重复,主要有两个实现类:HashSet和TreeSet,HashSet类按照哈希算法来存取集合中对象,存取速度比较快,HashSet类还有一个子类LinkedHashSet类,不仅实现了哈希算法,而且实现了链表数据结构,提高数据结构的插入和删除元素的性能,TreeSet类实现了SortedSet接口,具有排序功能。

看下这个程序:

package com.bin.proxy;

import java.util.HashSet;

import java.util.Set;

public class Test4 {

public static void main(String[] args){

Set set = new HashSet();

String s1="hello";

String s2=s1;

String s3=new String("world");

set.add(s1);

set.add(s2);

set.add(s3);

System.out.print(s2.equals(s1));

System.out.print(set.size());

}

}

把s2 的对象引用赋值给s1,则2个位同一个引用,值是相同的。Set采用equals()比较对象是否相等。而不是“==”。

HastSet类

我们先从HashSet源码看起:

下面是HashSet的定义:

1public classHashSet

2extendsAbstractSet

3implementsSet,Cloneable,java.io.Serializable

HashSet继承了AbstractSet,实现了Set接口。其实AbstractSet已经实现Set接口了。AbstractSet继承自AbstractCollection,而AbstractCollection实现了Collection接口的部分方法,而Set接口和Collection接口完全一致,所以AbstractSet只是实现了AbstractCollection没有实现的Set接口的方法和重写了部分AbstractCollection已经实现的方法。AbstractSet实现了equql()、hashCode()、removeAll()功能的重写。

再看HashSet

下面是HashSet定义的属性:

1private transient HashMap map;

2private static final Object PRESENT = new Object();

想一下HashMap有什么特点:基于哈希表,存储键值对,Key不能相同等等。Key不能相同!这个特点是不是和Set的元素不能相同和类似?如果将Set的元素当成Map的Key,是否就保证了元素的不重复?!答案是肯定的。但是Map存储键值对,Key有了,那么Value呢?这正是第二个属性PERSENT的意义。看到PERSENT属性时一个Object对象,且是static和final的,它的用途就是当做Value存进map中。

总结一下,HashSet的实现方式大致如下,通过一个HashMap存储元素,元素是存放在HashMap的Key中,而Value统一使用一个Object对象。

这样看来HashSet应该很简单,应该只是使用了HashMap的部分内容来实现。

看下add()方法源码 ,即是通过HashMap实现,

public boolean add(E e) {

returnmap.put(e,PRESENT)==null;

}

addAll方式是在抽象类AbstractCollection中实现,HashSet通过继承拥有该方法,采用循环插入实现。

public boolean addAll(Collection extends E> c) {

boolean modified = false;

for (E e : c)

if (add(e))

modified = true;

return modified;

}

iterator()

public Iterator iterator() {

returnmap.keySet().iterator();

}

很清楚了,返回的是HashMap中KeySet的迭代器。

size()

public int size() {

return map.size();

}

size()方法同样返回的是map的大小,所以HashSet根本就没定义size属性。

public boolean isEmpty() {

return map.isEmpty();

}

既然size()用的是map的大小,那么isEmpty()自然也是判断map。

public boolean contains(Object o) {

return map.containsKey(o);

}

public voidclear() {

map.clear();

}

public Objectclone() {

try {

HashSet newSet =(HashSet) super.clone();

newSet.map = (HashMap) map.clone();

return newSet;

} catch (CloneNotSupportedException e) {

throw new InternalError();

}

}

这几个方法就不解释了。

public boolean remove(Object o) {

return map.remove(o)==PRESENT;

}

remove(Object o)为什么还要判断结果呢?因为通过HashSet存入的元素,所对应的Value值都是PERSENT,如果传入的o不存在,map的remove方法返回为null,则对应的结果是HashSet的remove操作应该放回false,所以这里根据返回的结果判断是否移除成功。

在Object类中定义了hashCode()和equals()方法,equals()方法按照内存地址比较对象是否相等,因此如果object1.equals(object2)为true,则表明两个变量引用同一个对象,其哈希码也肯定相等。如果用户定义一个类覆盖了Object类的equals()方法,但没有覆盖Object类的hashCode()方法,就会会导致,当object1.equals(object2)为true,而哈希码不一定一样,导致HashSet或HashMap无法正常工作。

package com.bin.proxy;

class Customer {

String name;

int 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;

}

public boolean equals(Object o){

if(this ==o)returntrue;

if((o instanceof Test5))returnfalse;

final Customer test=(Customer)o;

if(this.name.equals(test.getName())&&this.age==test.getAge())

return true;

else

return false;

}

public int hashCode(){

int result;

result=(name ==null?0:name.hashCode());

result = 29*result+age;

return result;

}

}

public class Test5{

public static void main(String[] args){

Customer t1= new Customer();

Customer t2= new Customer();

t1.setAge(4);

t1.setName("song");

t2.setAge(4);

t2.setName("song");

System.out.print(t1.equals(t2));

}

}

如上程序,若把hashCode()去掉,则在HashSet和HashMap代表不同的对象。

四、TreeSet类

其构造方法为:

构造方法摘要

Collection extendsE> c) 构造一个包含指定 collection 元素的新 TreeSet,它按照其元素的自然顺序进行排序。

Comparator superE> comparator) 构造一个新的空 TreeSet,它根据指定比较器进行排序。

SortedSet s) 构造一个与指定有序 set 具有相同映射关系和相同排序的新 TreeSet。

例程:

Setset =new TreeSet();

set.add(newInteger(8));

set.add(new Integer(7));

set.add(new Integer(9));

则程序打印set时显示 6 7 8 9。

TreeSet支持两种排序方式:自然排序和客户化排序,默认采用自然排序

1、 自然排序

在JDK中有个Comparable接口,部分类实现了他,如Integer,Double和String等,其有个接口compareTo(Object o)方法,x.compareTo(y),返回0,表示相等,若大于0表示x大于y,反之小于0,表示x小于y。

TreeSet调用compareTo()方法比较集合对象的大小,然后进行升序排序,成为自然排序,使用自然排序的时候,只能想TreeSetJ集合加入同类型的对象,这些对象必须实现了Comparable接口,

2、 客户化排序

除了自然排序,TreeSet还支持客户化排序,java.util.Comparator接口提供具体排序方式,Comparator有个compare(Type x,Type y)方法,用于比较对象大小,当返回大于0时,表示x大于y,当放回小于0时,表示x小于y,当返回等于0时,表示x等于y

package com.bin.jihe;

import java.util.Comparator;

import java.util.Iterator;

import java.util.Set;

import java.util.TreeSet;

public class CustomerComparator implements Comparator{

public static void main(String[] args) {

Set set=new TreeSet(newCustomerComparator());

set.add(new Customer(11,"tom"));

set.add(new Customer(12,"jim"));

set.add(new Customer(10,"ljcy"));

Iterator it=set.iterator();

while(it.hasNext()){

Customer customer=it.next();

System.out.println(customer.getAge()+"-"+customer.getName());

}

}

@Override

public int compare(Customer o1, Customer o2) {

if(o1.getName().compareTo(o2.getName())>0)return 1;

if(o1.getName().compareTo(o2.getName())<0)return -1;

return 0;

}

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值