Andy Back-end Dev Engineer

Java基础-容器中的设计模式


迭代器设计模式

为了符合开闭原则,Java容器中采用了迭代器的设计模式,具体可参考迭代器模式 iterator

对以下代码分析:

Collection<String> c = new ArrayList<>();
Iterator<String> iterator = c.iterator();

在编译期c.iterator()会检查Collection中有没有iterator()方法。在运行时会调用ArrayList中的iterator()方法。

public Iterator<E> iterator() {
    return new Itr();
}

private class Itr implements Iterator<E> {
    int cursor;       // index of next element to return
    int lastRet = -1; // index of last element returned; -1 if no such
    int expectedModCount = modCount;

    public boolean hasNext() {
        return cursor != size;
    }
    
    @SuppressWarnings("unchecked")
    public E next() {
        checkForComodification();
        int i = cursor;
        if (i >= size)
            throw new NoSuchElementException();
        Object[] elementData = ArrayList.this.elementData;
        if (i >= elementData.length)
            throw new ConcurrentModificationException();
        cursor = i + 1;
        return (E) elementData[lastRet = i];
    }
    // ...

可以看出返回的iterator是由ArrayList实现的。

注意: 1.List底层是数组实现,所以可以支持get(index)方法获取集合对象。 2.List支持ListIterator,可以用hasPrevious()和hasPrevious()实现逆向遍历,但是必须先正向遍历才可,所以一般不使用。 3.并发修改异常:CurrentModificationException

  • 产生的原因:迭代器是依赖于集合的,当用迭代器进行遍历的时候,对集合进行了修改,此时的迭代器并不知道,所以产生并发修改异常。
  • 解决方法: 1.集合遍历,集合修改,此时新加的元素在最后 2.迭代器遍历,迭代器修改,此时新加的元素在刚才迭代的元素后面。

适配器模式

public static <T> List<T> asList(T... a)

可以使用以上方法将数组类型转化为List,但是有几个注意点。 1.asList()的参数为泛型的可变参数,本质是一个数组,要求里面的参数必须是引用类型,即基本类型只能使用包装类型。 2.由于参数本质是数组,所以转为list之后还是数组,不能对数组的长度进行改变,即不能使用add,remove方法,可以使用set方法。 代码举例:

List<String> list = Arrays.asList("hello", "minmin");
list.add("love");  // 报错
list.remove("love"); // 报错
list.set(1, "java"); // 可以执行

参考资料: 集合中的设计模式 Java与模式


Comments

Content