博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java集合学习之Collection(2)
阅读量:2227 次
发布时间:2019-05-09

本文共 4244 字,大约阅读时间需要 14 分钟。

上篇博客讲了Collection接口的一些基本操作,这篇博客主要介绍Collection接口的子接口Set。

Set是一种无序的集合,其基本操作和Collection接口是差不多的,主要的不同点在于Set中不能重复元素而Collection集合是可以的。对于Set集合我们主要关心它的HashSet,TreeSet两个实现类。

一.HashSet

HashSet是Set接口的典型实现,大多数时候使用Set集合时就是使用这个类;HashSet通过hash算法确定元素的存储位置。值得注意的是HashSet中可以存储值为null的元素。
那么HashSet是怎样工作的呢?我们每传入一个元素,HashSet就调用该对象的HashCode()方法计算得到该对象的HashCode值,然后就根据这个值决定该元素在HashSet中的存储位置。如果两个对象通过equals()比较相等,但是计算出的HashCode值不相同,那么HashSet就将他们存储到不同的位置上去;如果两个对象的HashCode值相等,而通过equals()方法比较不相等,那么HashSet就将他们在同一个位置上以链表的形式存储。
综上我们可以知道HashSet判断两个对象相等的标准是:两个对象的HashCode值相同,并且两个对象通过equals()方法比较返回true。所以这两个方法对HashSet来说是十分重要的,我们需要保证当两个对象的HashCode值一样时,其通过equals()方法比较也会返回true。下面的程序中A,B,C类分别重写了自己的HashCode()和equals()方法。

public class A {    ///重写A类的equals()方法,使其总是返回true    public boolean equals(Object obj){        return true;    }}public class B {    ///重写B类的HashCode()方法,使其总是返回2    public int hashCode(){        return 2;    }}public class C {    ///重写C类的equals()方法,使其总是返回true    public boolean equals(Object obj){        return true;    }    ///重写C类的HashCode()方法,使其总是返回3    public int hashCode(){        return 3;    }}public class HashCodeTest {    public static void main(String[] args){        HashSet st = new HashSet();        //依次添加两个A,B,C类对象        st.add(new A());         st.add(new A());        st.add(new B());        st.add(new B());        st.add(new C());        st.add(new C());        //可以看到只输出了一个C类,而A,B类都输出了两个        System.out.println(st);    }}

HashSet有一个叫LinkedHashSet的子类,LinkedHashSet的基本原理和HashSet是一样的,只是LinkedHashSet内部通过一个链表来维护插入元素的相对顺序,这样使得看起来元素是以插入的顺序保存的;当我们遍历LinkedHashSet时就可以将元素以其输入顺序输出了。

package lkl;import java.util.LinkedHashSet;public class LinkedHashSetTest {    public static void main(String[] args){        LinkedHashSet lt = new LinkedHashSet();        lt.add("java");        lt.add("c");        lt.add("c++");        lt.add("shell");        ///从下面两次输出可以看出,元素总是以输入顺序输出        System.out.println(lt);        lt.remove("java");        lt.add("java");  ///从新添加后java被放到最后        System.out.println(lt);    }}

二.TreeSet

TreeSet是Set的另一个重要的子类。与HashSet通过hash的方式确定元素的存储位置不同,TreeSet内部通过一棵红黑树来维护元素的相对次序;由于TreeSet中元素的有序性,相对HashSet,还提供了几个额外的方法,如下面的代码所示:

package lkl;import java.util.TreeSet;public class TreeSetTest {public static void main(String[] args){    TreeSet ts = new TreeSet();    ts.add(1);    ts.add(-2);    ts.add(7);    ts.add(4);    ///从下面的输出可以看出TreeSet是有序的    System.out.println(ts);    ///Comparator comparator()    ///如果TreeSet采用了定制排序,则返回定制排序的Comparator    ///如果采用了自然排序,则返回null    System.out.println(ts.comparator());    ///Object first():返回集合中第一个元素    ///Object last():返回集合中最后一个元素    System.out.println("集合中第一个元素为: "+ts.first());    System.out.println("集合中最后一个元素为: "+ts.last());    ///Object lower(Object e):返回集合中第一个小于e的元素,e不一定在集合中    ///Object higher(Object e):返回集合中第一个大于e的元素    ///如果没有元素满足的话,返回null    System.out.println("集合中第一个小于5的元素是: "+ts.lower(5));    System.out.println("集合中第一个大于5的元素是: "+ts.higher(5));    ///SortedSet subSet(Object e1,Object e2):返回Set从e1-e2之间的子集    System.out.println(ts.subSet(1,5));    ///SortSet headSet(Object e):返回集合中小于e的元素组成的子集    System.out.println(ts.headSet(6));    ///SortSet tailSet(Object e):返回集合中大于等于e元素组成的子集    System.out.println(ts.tailSet(1));}}

因为TreeSet是有序的,所以插入一个元素时总是要比较大小;这里进行大小比较时总是调用对象obj1.compareTo(Object obj2)方法(返回正整数表示obj1大于obj2,返回负整数时表示obj1小于obj2,返回0时表示相等),只有两个对象通过compareTo()比较返回0时,才认为两个对象相等。这导致一个问题,不同的对象不能被同时插入到TreeSet中,因为不同的对象不能通过comparaTo()方法进行比较;当我们将不同的对象插入到TreeSet中时会引发异常。

如果我们想自己定义排序的规则,我们可以借助Comparator接口。该接口中包含了一个int compare(T t1,T t2)的方法,该方法在t1>t2时返回正整数,在t1

package lkl;import java.util.TreeSet;import java.util.Comparator;public class TreeSetComparatorTest {///TreeSet原本是从从小到大输出的,现在自己定制排序后///可以实现从大到小输出    public static void main(String[] args){        TreeSet ts = new TreeSet(new Comparator(){           public int compare(Object o1,Object o2){                int m1= (int)o1;                int m2= (int)o2;                if(m1==m2)                    return 0;                if(m1>m2)                    return -1;                return 1;            }        });        ts.add(1);        ts.add(2);        ts.add(-1);        System.out.println(ts);    }}

最后要强调一句,如果我们向set中添加了可变的对象,然后又改变了该对象中的File,那么可能造成该对象在set中”不可见”的情况;如果我们向set中加入了可变的对象,那么我们不要在后面再改变其中File的值。

转载地址:http://zurfb.baihongyu.com/

你可能感兴趣的文章
Chrome开发者工具
查看>>
【LEETCODE】102-Binary Tree Level Order Traversal
查看>>
【LEETCODE】106-Construct Binary Tree from Inorder and Postorder Traversal
查看>>
【LEETCODE】202-Happy Number
查看>>
和机器学习和计算机视觉相关的数学
查看>>
十个值得一试的开源深度学习框架
查看>>
【LEETCODE】240-Search a 2D Matrix II
查看>>
【LEETCODE】53-Maximum Subarray
查看>>
【LEETCODE】215-Kth Largest Element in an Array
查看>>
【LEETCODE】241-Different Ways to Add Parentheses
查看>>
【LEETCODE】312-Burst Balloons
查看>>
【LEETCODE】232-Implement Queue using Stacks
查看>>
【LEETCODE】225-Implement Stack using Queues
查看>>
【LEETCODE】155-Min Stack
查看>>
【LEETCODE】20-Valid Parentheses
查看>>
【LEETCODE】290-Word Pattern
查看>>
【LEETCODE】36-Valid Sudoku
查看>>
【LEETCODE】205-Isomorphic Strings
查看>>
【LEETCODE】204-Count Primes
查看>>
【LEETCODE】228-Summary Ranges
查看>>