java set集合转数组_java-集合体系中的Set和Map

java的集合体系分为两类,一类是Collection,一类是Map体系。详细见下图:

61d545de1acaca60867ff5c5fa6f8717.png

Collection是指一组元素的集合,比如常用的ArrayList,LinkedList,HashSet、linkedHashSet、TreeSet等,而Map则是一组键值对的集合,比如常用的HashMap,LinkedHashMap等。

这里不赘述具体的api用法,而是讲讲map和set之间的联系,比如HashMap和HashSet,看下HashSet内部的接口:

1、HashSet并没有提供get某个元素的方式,只提供了contains方法用于判断是否包含某个元素:

ba6940a599ca6a1220366e5496242f7c.png

400afb2bf3e5464f979055197c80107e.png

2、对于add方法,内部使用了HashMap去存储,把我们要入set的元素放到map的key上:

private transient HashMap<E,Object> map;
public boolean add(E e) {
    return map.put(e, PRESENT)==null;
}

3、contains方法实现是map.containsKey():

public boolean contains(Object o) {
    return map.containsKey(o);
}

由上述几点可初步得出结论:HashSet是在内部是通过HashMap实现的。

那是否又可以推出另外一个结论就是,Set体系的类,其内部是通过Map类去实现的?观察下TreeMap的add方法:

private transient NavigableMap<E,Object> m;
public boolean add(E e) {
    return m.put(e, PRESENT)==null;
}

进一步坐实“Set体系的类,其内部是通过Map类去实现”这个结论。

Set中存在HashSet、LinkedHashSet、TreeSet这几个比较常用的类,名称上相似,但实际联系是什么呢?本质的联系是,HashSet不保证添加和输出的元素顺序一致,LinkedHashSet则保证添加和输出的顺序一致,而TreeSet则是保证输出的结果按照从小到大自然排序,如下方示例代码:

Set<Integer> set1 = new HashSet<Integer>();
Set<Integer> set2 = new LinkedHashSet<Integer>();
Set<Integer> set3 = new TreeSet<Integer>();

List<Integer> list = new ArrayList<Integer>(Arrays.asList(1000, 2, 9, -5, 16));

set1.addAll(list);
set2.addAll(list);
set3.addAll(list);

System.out.println("HashSet="+set1);//[16, 2, -5, 1000, 9] 不保证插入和输出的顺序一致
System.out.println("LinkedHashSet="+set2);//[1000, 2, 9, -5, 16] 保证插入和输出的顺序一致
System.out.println("TreeSet="+set3);//[-5, 2, 9, 16, 1000] 默认从小到大进行排序,如果要控制顺序,可以传递Comparator参数

set内部是由map实现的,自然map中也有类似的实现:LinkedHashMap、HashMap以及TreeMap,把两者类比起来边得到下面的关联,彼此之间的性质是相类似的:

1、LinkedHashSet和LinkedHashMap
2、HashSet和HashMap
3、TreeSet和TreeMap

map中存在一个比较坑的地方,map.keySet会返回内部对象的引用,如果外部对其进行操作,会影响map的内部状态:

Map<String, String> map = new HashMap<String, String>();
map.put("attrOne", "aaaa");
map.put("attrTwo", "bbb");
map.put("attrThree", "ccc");

Set<String> keys = map.keySet();
List<String> values = new ArrayList<String>(map.values());//要写成这种语法,我也是醉了。。。直接向下转型会直接报错
System.out.println("key size="+keys.size());//3
System.out.println("value size="+values.size());//3
map.remove("attrTwo");
System.out.println("key size="+keys.size());//2 这里反映出,map.keySet返回的是内部的引用类型,可变,会导致潜在的bug
System.out.println("value size="+values.size());//3

由这一点可以看出,map的接口设计其实有问题,即不应该返回内部引用对象给外界,避免出bug,这一个原则在 《effective java》第50条讲到,必要时进行保护性拷贝。具体可参见原书,大意为如下伪代码:

class MyHashMap{
    private HashMap map= new HashMap();
    public Set keySet(){
        return new HashSet(map.keySet());
    }
}

通过类似的接口封装,把keySet的结果简单复制下,外部对返回的set做任何操作,也就不会影响到Map的状态。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值