美文网首页
java复习

java复习

作者: Dottie22 | 来源:发表于2016-12-20 00:43 被阅读30次

    Iterator和Enumeration的区别

    我们通常用Iterator(迭代器)或者Enumeration(枚举器)去遍历集合, 那么这个类有何区别?

    直接上源码:
    package java.util
    public interface Enmeration<E> {
        boolean hasMoreElements();
        E nextElement();
    }
    
    package java.util
    public interface Iterator<E> {
        boolean hasNext();
        E next();
        void remove(); **//迭代器这里比枚举器多一个方法哦.**
    }
    

    迭代器和枚举器的区别

    1. 枚举器(Enumberation)只提供了两个接口方法, 意味着我们只能读取数据.
    2. 迭代器(Iterator)在枚举器基础了又提供了一个对数据删除的操作.
    3. Iterator支持'Fail-Fast机制', 而Enumeration不支持.
    4. 枚举遍历的效率比迭代器效率高.

    fail-fast简介

    fail-fast机制是java集合(Collection)中的一中错误机制, 当多个线程对同一个集合的内容进行操作时, 就可能产生fail-fast事件.
    如:
    当一个线程A通过iterator去遍历某集合的过程中, 若该集合的内容被其他线程改变了, 那么线程A访问集合时, 就会抛出ConcurrentModificationException异常,产生fail-fast事件.

    简单点说:线程A遍历集合list的过程中, list的内容被另外一个线程所改变了.就会抛出ConcurrentModificationException异常,即产生fail-fast事件.

    fail-fast解决办法

    fail-fast机制,是一种错误检测机制, 它只能被用来检测错误, 以为JDK并不保证fail-fast机制一定会发生.

    具体分析:
    产生fail-fast事件,是通过抛出ConcurrentModificationException异常来触发的。
    那么,ArrayList是如何抛出ConcurrentModificationException异常的呢?

    我们知道,ConcurrentModificationException是在操作Iterator时抛出的异常。我们先看看
    Iterator的源码。ArrayList的Iterator是在父类AbstractList.java中实现的。代码如下:

    package java.util;
    
    public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
    
        ...
    
        // AbstractList中唯一的属性
        // 用来记录List修改的次数:每修改一次(添加/删除等操作),将modCount+1
        protected transient int modCount = 0;
    
        // 返回List对应迭代器。实际上,是返回Itr对象。
        public Iterator<E> iterator() {
            return new Itr();
        }
         //在AbstractList类中找到了Itr类的具体实现,它是AbstractList的一个成员内部类,
        // Itr是Iterator(迭代器)的实现类
        private class Itr implements Iterator<E> {
             //cursor:表示下一个要访问的元素的索引,从next()方法的具体实现就可看出
            int cursor = 0;
             //lastRet:表示上一个访问的元素的索引
            int lastRet = -1;
             //expectedModCount:表示对ArrayList修改次数的期望值,它的初始值为modCount。
            // 修改数的记录值。
            // 每次新建Itr()对象时,都会保存新建该对象时对应的modCount;
            // 以后每次遍历List中的元素的时候,都会比较expectedModCount和modCount是否相等;
            // 若不相等,则抛出ConcurrentModificationException异常,产生fail-fast事件。
            int expectedModCount = modCount;
    
            public boolean hasNext() {
                return cursor != size();
            }
    
            public E next() {
                // 获取下一个元素之前,都会判断“新建Itr对象时保存的modCount”和“当前的modCount”是否相等;
                // 若不相等,则抛出ConcurrentModificationException异常,产生fail-fast事件。
                checkForComodification();
                try {
                    E next = get(cursor);
                    lastRet = cursor++;
                    return next;
                } catch (IndexOutOfBoundsException e) {
                    checkForComodification();
                    throw new NoSuchElementException();
                }
            }
    
            public void remove() {
                if (lastRet == -1)
                    throw new IllegalStateException();
                checkForComodification();
    
                try {
                    AbstractList.this.remove(lastRet);
                    if (lastRet < cursor)
                        cursor--;
                    lastRet = -1;
                    expectedModCount = modCount;
                } catch (IndexOutOfBoundsException e) {
                    throw new ConcurrentModificationException();
                }
            }
    
            final void checkForComodification() {
                if (modCount != expectedModCount)
                    throw new ConcurrentModificationException();
            }
        }
    
        ...
    }
        
    

    从中,我们可以发现在调用 next() 和 remove()时,都会执行 checkForComodification()。若 “modCount 不等于 expectedModCount”,则抛出ConcurrentModificationException异常,产生fail-fast事件。

    1. 在单线程下,细心的朋友可能发现在Itr类中也给出了一个remove()方法:

    public void remove() {
        if (lastRet == -1)
        throw new IllegalStateException();
           checkForComodification();
     
        try {
        AbstractList.this.remove(lastRet);
        if (lastRet < cursor)
            cursor--;
        lastRet = -1;
        expectedModCount = modCount;
        } catch (IndexOutOfBoundsException e) {
        throw new ConcurrentModificationException();
        }
    }
    
    

    在这个方法中,删除元素实际上调用的就是list.remove()方法,但是它多了一个操作:

    expectedModCount = modCount;
    因此,在迭代器中如果要删除元素的话,需要调用Itr类的remove方法。
    

    代码举例:

    public class Test {
        public static void main(String[] args)  {
            ArrayList<Integer> list = new ArrayList<Integer>();
            list.add(2);
            Iterator<Integer> iterator = list.iterator();
            while(iterator.hasNext()){
                Integer integer = iterator.next();
                if(integer==2)
                    iterator.remove();   //注意这个地方
            }
        }
    }
    

    2. 如果在多线程编程下

    • 最好用java.util.concurrent包下的类去取代java.util包下的类.
    • 1)在使用iterator迭代的时候使用synchronized或者Lock进行同步;
    • 2)使用并发容器CopyOnWriteArrayList代替ArrayList和Vector。

    数组和集合排序

    public class Person implements Comparable<Person>{
    
        private String name;
        private int age;
    
        @Override
        public int compareTo(Person o) {
            if(o.age > this.age) return 1;
            return -1;
        }
    }
    
    public static void main(String[] args) {
        Person[] persons = new Person[10];
            for (int i = 0; i < 10; i++) {
    
                Person person = new Person("daejong", (new Random()).nextInt(30)+1);
                persons[i] = person;
            }
            //Person实现了Comparable的内部排序法.
            Arrays.sort(persons);
            
            //指定一个比较器, 很灵活的进行排序, 外部排序法
            Arrays.sort(persons, new Comparator<Person>() {
                @Override
                public int compare(Person o1, Person o2) {
    
                    if(o1.getAge() > o2.getAge()) return 1;
                    return -1;
                }
            });
    }
    

    集合Collections是专门处理容器的类,该类的Collections.sort()类似Arrays.sort()只是作用的
    对象不一样而已.

    /*
    * Collections类似Arrays, 是对Collection类的一些类方法,HashMap, treeMap, HashSet, treeSet, ArrayList, LinkedList
    * 附加注意:
    *
    Map.Entry
    Iterator
    Enumeration
    HashMap: 最多允许一条记录的键为null, 允许多条记录的值为null.
    Hashtable: 不允许键或值为空.
    LinkedHashMap: 保存了插入的顺序.
    TreeMap: 默认按照键升序排序.
    *
    Collections.sort(List<T> list); //T中实现内部排序接口
    Collections.sort(List<T> Comparator<? super T>c); //执行一个比较器 进行排序.
    * */
    

    排序总结

    /*
    * Comparator和Comparable比较
    1.Comparable是排序接口, 若一个类实现了Comparable接口, 就意味着该类支持排序. 要实现CompareTo(T o)方法
    2.而Comparator是比较器, 我们如果需要控制某个类的次序, 可以创建一个该类的比较器来进行排序. 要实现Compare(T o1, T o2)方法.
    3. 不难发现, Comparable相当于'内部比较器', Comparator相当于'外部比较器'.
    * */
    
    /*
    * Arrays排序都是经过调优的快速排序
    * 1. 对基本类型的数组进行排序, Arrays提供了默认的升序排序,没有提供相应的降序排序
    * 2. 若要对基本数据类型进行降序排序, 需要将这些数组转化为对应的封装类数组. 如Integer[], Double[], Character[]
    * */
    
    

    相关文章

      网友评论

          本文标题:java复习

          本文链接:https://www.haomeiwen.com/subject/xrrxvttx.html