面试时java集合中的一些要点

一、概览

    1.先来一张疯狂java的图


    2.再来一张带注释的


    3.再来一张接口图


二、Interator

    描述:iterator必须依附于collection对象,iterator本身并不提供盛装对象的能力,如果需要需要创建iterator对象,必须有一个被迭代的集合

    1.主要有三个方法

        boolean hasNext():如果被迭代的集合元素还没有被遍历完,则返回true

        Object next():返回集合中当前元素

        void remove():删除集合里当前的元素

    2.关于hasNext和next

  public class InteratorTest {
    public static void main(String[] args) {
        Collection collection = new ArrayList();
        collection.add("a");
        collection.add("b");
        collection.add("c");

       Iterator iterator =  collection.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());         //1
            String one = (String)iterator.next();        //2
        }
    }
}

上述代码会在2处报错。报错信息

Exception in thread "main" java.util.NoSuchElementException
	at java.util.ArrayList$Itr.next(ArrayList.java:854)
	at test.InteratorTest.main(InteratorTest.java:20)
a
c

原因:因为上述的代码用了两个next,第一次循环在1处拿到的值是“a”,在2处拿到的是“b”。第二次循环while用iterator.hasNext(),判断还有一个“c”元素存在,所以接着走循环,在1处拿到“c”,在2处因为没有元素可再拿了,就会报错了。所以在iterator循环中尽量避免有两个或者两个以上的iterator.next()存在。要记住,一个娘有时候养不活两个儿子呀! 

    3.关于remove

 public static void main(String[] args) {
        Collection collection = new ArrayList();
        collection.add("1");
        collection.add("2");
        collection.add("3");

       Iterator iterator =  collection.iterator();
        while (iterator.hasNext()){
            String one = (String)iterator.next();
            System.out.println(one);
            if(one.equals("2")){
                iterator.remove();                //1
            }
        }

        Iterator iterator2 =  collection.iterator();
        while (iterator2.hasNext()){
            System.out.println(iterator2.next());
        }

    }

上述代码输出:

1
2
3
1

3

当使用iterator迭代访问Collection集合元素时,Collection集合里的元素不能被改变,只有通过iterator的remove方法删除当前next方法返回的集合元素时才可以,否则会发生ConcurrentModificationException。上述代码如果把1处的代码换成

collection.remove(one)

就会引发该异常

注:iterator迭代器采用的是快速失败的机制,一旦在迭代过程中检测到该集合已经被修改(通常是程序中其他线程修改),程序立即已发ConcurrentModificationException,而不是显示修改后的结果,这样可以避免共享资源而引发的潜在问题。

三、set集合

    描述:set是一个不允许包含相同元素的无序集合,如果试图把两个相同的元素加入同一个set中,则添加操作失败,add方法返回false。

                set判断两个对象是否相同是根据equals方法。也就是说,只要两个对象用equals方法比较返回true,set就不会接受这两个对象,反之只要两个对象用equals方法比较返回false,set就会接受这两个对象(甚至这两个对象是同一个对象,set也可把他们当成两个对象来处理)

 1.HashSet

       特点:

        1)hashset不是线程安全的

        2)判断一个元素是否相等是通过equals()和hashCode()方法来判断的,只有两个方法都返回true才能判定两个元素相等,也就是说如果equals()和hashCode()有任何一个方法返回false,元素就会被储存成功

    

    equals和hashcode

        hashset中每个能存储元素的“槽位”通常称为“桶”(bucket)

        1)equals 为true, hashcode为false  元素会被存放在hash表中不同的桶当中

       2)  equals为false,hashcode为true     元素会被以链式结构存放在同一个桶当中;通常这是一种比较糟糕情况,因为hashset访问元素是根据hashcode的值来快速定位的,如果hashcode一个桶中有多个元素,那么就会导致性能下降

    总结:所以在重写equals方法的时候一定要重写hashcode方法,以保证equals方法和hashcode方法返回值应该保持一致。(要返回true都返回true,要返回false都返回false)

    1.1 LinkedHashSet

            特点:

           1) LinkedHashSet为Hashset的子类

           2) 使用链表维护元素的顺序,所以删除、插入性能会略低于hashSet,但是在迭代访问set里的全部元素的时候比hashset性能。好

    2.  TreeSet

        TreeSet是SortedSet接口的实现类,正如SortedSet名字所暗示的,TreeSet可以确保集合元素处于排序状态,他并不是根据插入顺序进行排序的,而是根据元素实际值的大小进行排序的。

              特点:

                    1)集合元素根据实际值的大小排序

                    2)利用红黑树的数据接口来存储集合元素

                    3)支持两种排序:自然排序、定制排序

                     4)因为该集合需要额外的用红黑树算法来维护集合元素的次序,所以他的性能总是比HashSet差的,所以除非需要保持排序,否则应该使用Hashset

             2.1自然排序

                    定义:TreeSet会调用集合元素的CompareTo(Object obj)方法来比较元素之间的大小关系,然后将集合元素按升序排序,这种方式就是自然排序

                        compareTo方法

             此方法用于判断两个对象是否相等和比较大小从而对两个对象进行排序,如两个对象进行比较:obj1.compareTo (obj2)  结果如下  

                                返回值          比较结果              

                                正整数            obj1>obj2

                                0                    obj1=obj2

                                负整数            obj1<obj2


                    Comparable

                    TreeSet中的元素必须实现Comparable接口,必须实现该接口中的compareTo方法。如下代码:Err没有实现该接口,将会报ClassCastException

public static void main(String[] args) 
	{
		TreeSet ts = new TreeSet();
		//向TreeSet集合中添加两个Err对象
		ts.add(new Err());
		ts.add(new Err());  //1
	}

                    注1:当添加第一个对象时,TreeSet中没有任何元素,所以不会出现问题,当添加第二个元素时,TreeSet就会调用该对象的 compareTo进行与集合中的其他元素进行对比,如果对应的其他的类没有实现Comparable接口,就会引发异常。

                    注2:java中大部分类在实现compareTo方法时都强制转换成相同的类型去做比较,所以在把这类对象放到TreeSet中,必须是同一类型的对象,不然会报ClassCastException

                    注3:自定义对象,当把两个对象依次放入TreeSet中时,就会调用compareTo去做两个对象是否相等,如果返回0,那么两个对象是相等的添加失败,如果不返回0,那么两个对象是不相等的可以添加成功。所以能否添加成功的唯一标准就是compareTo是否返回0.那么就会出现如下问题

package test.Treeset;

import java.util.TreeSet;

/**
 * Created by Administrator on 2018/2/28.
 */
 class Z implements Comparable{
    public int age;
    public Z (int age){
        this.age = age;
    }


    public int compareTo(Object o) {
        return 0;
    }

    public boolean equals(Object obj){
        return false;
    }
}

public class TreeSetTest{
    public static void main(String[] args) {
        TreeSet<Z> treeSet = new TreeSet();
        Z z1 = new Z(6);
        Z z2 = new Z(6);
        treeSet.add(z1);
        treeSet.add(z2);//1
    }
}

上面程序尽管两个对象equals为false,但是compareTo对比后为0,所以1处的添加是失败的。这就违背了set的规则。

所以在重写equals方法时,如果没有特殊的要求那么equels的返回值应该和compareTo方法的返回值保持一致。如:

        equals        compareTo

        true                0

        false                1


                    2.2定制排序

        日后再写

发布了14 篇原创文章 · 获赞 8 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/langwuzhe/article/details/79371824