精华内容
下载资源
问答
  • 实现like个集合

    千次阅读 2018-04-16 16:58:19
    SELECT A.* FROM B_GroupOrgTree A, B_GroupOrgTree_RelatedPerson B WHERE A.OrgIDFullPath LIKE '%'+B.OrgID+'%' and UserID='17FC402F-A1B2-4A36-AFD8-5A1D094E9992' AND PersonRoleEnumID=15523
    SELECT A.* FROM B_GroupOrgTree A, B_GroupOrgTree_RelatedPerson B
    
       WHERE A.OrgIDFullPath LIKE '%'+B.OrgID+'%'
       and UserID='17FC402F-A1B2-4A36-AFD8-5A1D094E9992' AND PersonRoleEnumID=15523
    展开全文
  • 超视觉 类似超视觉的自定义集合视图布局: 单击屏幕截图以查看实际布局的视频。 了解如何构建此布局
  • 集合运算到mysql的not like找不出NULL

    千次阅读 2019-08-21 18:22:58
    一个表,总记录数是1000条,现在有一条查询语句: #查询语句1 #找出表中id中含有‘A’或‘B’或‘C’的字段 select * from table1 where id like '%A%' or id like '%B%' or id like '%C%' ; #成功查出300条 嗯...

    记一次有趣的发现:

    有一个表,总记录数是1000条,现在有一条查询语句:

    #查询语句1
    #找出表中id中含有‘A’或‘B’或‘C’的字段
    select * from table1 where id like '%A%' or  id like '%B%' or  id like '%C%' ;
    #成功查出300条
    

    嗯查询正常,有300条记录呢。

    然后我随便再敲一次查询语句…:

    #查询语句2
    #找出表中id中不含有‘A’且不含有‘B’且不含有‘C’的字段
    select * from table1 where id not like '%A%' and  id not like '%B%' and  id not like '%C%' ;
    #成功查出400条
    

    嗯查出了400条呢…什么?!只有400条??不是应该700条吗!!!

    我如雷轰顶——哪里不对了??

    按道理,“找出表中id中含有‘A’或‘B’或‘C’的字段” 应该等价于 “找出表中id中不含有‘A’且不含有‘B’且不含有‘C’的字段” 的啊!这是由集合运算决定的啊!

    “找出表中id中含有‘A’或‘B’或‘C’的字段”>>看作>> A∪B∪C
    “找出表中id中不含有‘A’且不含有‘B’且不含有‘C’的字段”>>看作>> ∁UA∩∁UB∩∁UC

    然而我们根据运算规则可知:∁U(A∪B∪C) = ∁UA ∩ ∁UB ∩ ∁UC

    那就也是说,两条查询语句查出来的结果,不应该是互补的吗??理论上行数相加应该等于1000的呀,那现在怎么缺了300条呢?

    奇了怪了。到底哪里错了呢??

    于是换一条查询语句:

    #查询语句3
    #找出表中id中不含有‘A’或‘B’或‘C’的字段
    select * from table1 where id not in (select * from table1 where id like '%A%' or  id like '%B%' or  id like '%C%' );
    #成功查出700条
    

    咦??怎么这样查,才是查询语句1的互补集呢?

    我将查询语句2和查询语句3得到的结果一比较,发现:
    原来缺少的300条记录,是id 为NULL的情况!

    也就是说,not like ‘%A%’ 是不能查出NULL的记录的!

    经过了解,发现:
    在这里插入图片描述
    来源于https://zhidao.baidu.com/question/38304426.html

    又发现了一个细节知识~

    展开全文
  • Java 集合

    千次阅读 2016-02-07 10:52:36
    Java 集合标签: Java基础集合/容器Java集合由Collection Map两接口派生而出,Collection代表序列式容器,Map代表关联式容器.CollectionCollection作为List Queue Set等序列式容器的父接口, 提供了一些公共基础方法:...

    Java 集合

    标签 : Java基础


    集合/容器

    Java集合由Collection Map两个接口派生而出,Collection代表序列式容器,Map代表关联式容器.


    Collection

    Collection作为List Queue Set等序列式容器的父接口, 提供了一些公共基础方法:

    • update相关方法:
      boolean add(E e)
      boolean addAll(Collection<? extends E> c)
      void clear()
      boolean remove(Object o)
      boolean removeAll(Collection<?> c)
      boolean retainAll(Collection<?> c)(取交集)

    • select相关方法
      boolean contains(Object o)
      boolean containsAll(Collection<?> c)
      Iterator<E> iterator()
      Object[] toArray()
      <T> T[] toArray(T[] a)
      boolean isEmpty()
      int size()

    详细可参考JDK文档


    Iterator

    iterator()方法返回一个迭代器Iterator.与其他容器主要用于存储数据不同,Iterator主要用于遍历容器.
    Iterator隐藏了各类容器的底层实现细节,向应用程序提供了一个遍历容器的统一接口:

    方法释义
    boolean hasNext()Returns true if the iteration has more elements.
    E next()Returns the next element in the iteration.
    void remove()Removes from the underlying collection the last element returned by this iterator (optional operation).

    注意: 当遍历Collection时不要使用Collection自带的remove方法删除数据,确实需要删除时,需要使用Iterator提供的remove.

    /**
     * @author jifang
     * @since 16/1/25 上午9:59.
     */
    public class RemoveClient {
    
        Collection<Integer> collection = new ArrayList<>();
    
        @Before
        public void setUp() {
            Random random = new Random();
            for (int i = 0; i < 10; ++i) {
                collection.add(random.nextInt(i + 1));
            }
        }
    
        @Test
        public void client() {
            System.out.print("before:");
            for (Iterator<Integer> iterator = collection.iterator(); iterator.hasNext(); ) {
                Integer integer = iterator.next();
                System.out.printf(" %d", integer);
                if (integer == 0) {
                    //collection.remove(i);
                    iterator.remove();
                }
            }
            System.out.printf("%n after:");
            for (Integer integer : collection) {
                System.out.printf(" %d", integer);
            }
        }
    }

    Java 1.5提供foreach循环使得代码更加简洁,但实际foreach迭代容器元素底层也是用的Iterator,这一点可以在调试时看得很清楚.


    List

    List代表有序/可重复集合,因此ListCollection的基础上添加了根据索引来操作元素的方法:

    方法描述
    void add(int index, E element)Inserts the specified element at the specified position in this list (optional operation).
    E get(int index)Returns the element at the specified position in this list.
    int indexOf(Object o)Returns the index of the first occurrence of the specified element in this list, or -1 if this list does not contain the element.
    int lastIndexOf(Object o)Returns the index of the last occurrence of the specified element in this list, or -1 if this list does not contain the element.
    E remove(int index)Removes the element at the specified position in this list (optional operation).
    E set(int index, E element)Replaces the element at the specified position in this list with the specified element (optional operation).
    List<E> subList(int fromIndex, int toIndex)Returns a view of the portion of this list between the specified fromIndex, inclusive, and toIndex, exclusive.

    List判断两个元素是否相等是通过equals()方法.

    public int indexOf(Object o) {
        if (o == null) {
            for (int i = 0; i < size; i++)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = 0; i < size; i++)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }

    ListIterator

    List增加了返回ListIterator的方法:

    方法描述
    ListIterator<E> listIterator()Returns a list iterator over the elements in this list (in proper sequence).
    ListIterator<E> listIterator(int index)Returns a list iterator over the elements in this list (in proper sequence), starting at the specified position in the list.

    ListIterator继承自Iterator,专门用于操作List, 在Iterator的基础上增加了如下方法:

    方法描述
    void add(E e)Inserts the specified element into the list (optional operation).
    void set(E e)Replaces the last element returned by next() or previous() with the specified element (optional operation).
    boolean hasPrevious()Returns true if this list iterator has more elements when traversing the list in the reverse direction.
    E previous()Returns the previous element in the list and moves the cursor position backwards.
    int previousIndex()Returns the index of the element that would be returned by a subsequent call to previous().
    int nextIndex()Returns the index of the element that would be returned by a subsequent call to next().

    Iterator相比增加了前向迭代 获取迭代元素index 以及add set的功能.


    ArrayList

    ArrayListList基于数组的实现,它封装了一个动态自增长/允许再分配的Object[]数组:

    /**
     * The array buffer into which the elements of the ArrayList are stored.
     * The capacity of the ArrayList is the length of this array buffer. Any
     * empty ArrayList with elementData == EMPTY_ELEMENTDATA will be expanded to
     * DEFAULT_CAPACITY when the first element is added.
     */
    private transient Object[] elementData;

    ArrayList可以使用initialCapacity参数来设置该数组的初始长度ArrayList(int initialCapacity),或者使用默认长度DEFAULT_CAPACITY = 10; 当添加元素超过elementData数组容量时,ArrayList会重新分配数组, 以容纳新元素:

        /**
         * Appends the specified element to the end of this list.
         *
         * @param e element to be appended to this list
         * @return <tt>true</tt> (as specified by {@link Collection#add})
         */
        public boolean add(E e) {
            ensureCapacityInternal(size + 1);  // Increments modCount!!
            elementData[size++] = e;
            return true;
        }
        private void ensureCapacityInternal(int minCapacity) {
            if (elementData == EMPTY_ELEMENTDATA) {
                minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
            }
    
            ensureExplicitCapacity(minCapacity);
        }
    
        private void ensureExplicitCapacity(int minCapacity) {
            modCount++;
    
            // overflow-conscious code
            if (minCapacity - elementData.length > 0)
                grow(minCapacity);
        }
    
        /**
         * Increases the capacity to ensure that it can hold at least the
         * number of elements specified by the minimum capacity argument.
         *
         * @param minCapacity the desired minimum capacity
         */
        private void grow(int minCapacity) {
            // overflow-conscious code
            int oldCapacity = elementData.length;
            int newCapacity = oldCapacity + (oldCapacity >> 1);
            if (newCapacity - minCapacity < 0)
                newCapacity = minCapacity;
            if (newCapacity - MAX_ARRAY_SIZE > 0)
                newCapacity = hugeCapacity(minCapacity);
            // minCapacity is usually close to size, so this is a win:
            elementData = Arrays.copyOf(elementData, newCapacity);
        }

    如果在创建时就知道ArrayList的容量,最好同时指定initialCapacity的大小,以避免重新分配数组,耗费性能.

    ArrayList还提供如下方法来调整initialCapacity大小:

    方法描述
    void ensureCapacity(int minCapacity)Increases the capacity of this ArrayList instance, if necessary, to ensure that it can hold at least the number of elements specified by the minimum capacity argument.
    void trimToSize()Trims the capacity of this ArrayList instance to be the list’s current size.

    工具类Arrays还提供了一个static方法List<T> asList(T... a), 该方法可以把数组N个对象转换成一个List集合, 这个List集合并不是普通的ArrayList,而是Arrays内部实现的一个Arrays.ArrayList(一个固定长度的List,不可对该集合做add/remove操作).
    关于ArrayList实现原理还可以参考ArrayList源码解析


    LinkedList

    LinkedList是基于双向链表实现的List,虽然可以根据索引来访问集合中的元素,但性能不高(平均时间复杂度为O(N)),但其插入/删除操作非常迅速(尤其是在头尾,平均时间复杂度为O(1));除此之外,LinkedList还实现了Deque接口,因此还可以当成[双端]队列/栈来使用.
    关于LinkedList的实现原理还可以参考 [1.LinkedList源码解析, 2. 双向循环链表的设计与实现]

    /**
     * @author jifang
     * @since 16/1/23 下午9:07.
     */
    public class ListClient {
    
        private Random random = new Random();
    
        @Test
        public void client() {
            List<Integer> list = new LinkedList<>();
            for (int i = 0; i < 10; ++i) {
                list.add(random.nextInt(i + 1));
            }
    
            for (ListIterator<Integer> i = list.listIterator(); i.hasNext(); ) {
                if (i.next() == 0) {
                    i.set(188);
                    i.add(-1);
                }
            }
    
            System.out.println(list);
        }
    }

    Queue

    Queue用于模拟队列,队列是一种先进先出/FIFO容器,新元素插到队尾(offer), 访问操作会返回队首元素(poll). 通常, 队列不允许随机访问队列中的元素:

    方法描述
    boolean add(E e)Inserts the specified element into this queue if it is possible to do so immediately without violating capacity restrictions, returning true upon success and throwing an IllegalStateException if no space is currently available.
    boolean offer(E e)Inserts the specified element into this queue if it is possible to do so immediately without violating capacity restrictions.
    E element()Retrieves, but does not remove, the head of this queue.
    E peek()Retrieves, but does not remove, the head of this queue, or returns null if this queue is empty.
    E poll()Retrieves and removes the head of this queue, or returns null if this queue is empty.
    E remove()Retrieves and removes the head of this queue.

    Queue有一个PriorityQueue实现类,另外Queue还有一个Deque子接口,代表可以从两端存取数据的队列(因此Deque可以当成Stack使用),Java为Deque提供了ArrayDequeLinkedList两个实现类.


    PriorityQueue

    PriorityQueue并不是按照插入队列顺序进行排序,而是按照队列元素的大小(权重)进行排序, 因此element/peek/poll/remove返回的并不是最早进入队列的元素,而是队列中[权重]最小的元素:

    /**
     * @author jifang
     * @since 16/1/28 下午6:20.
     */
    public class QueueClient {
    
        @Test
        public void clientPriorityQueue() {
    
            Random random = new Random();
    
            Queue<Integer> queue = new PriorityQueue<>();
            for (int i = 0; i < 10; ++i) {
                queue.add(random.nextInt(100));
            }
    
            // 无序
            System.out.print("iterator:");
            for (Integer i : queue) {
                System.out.printf(" %d", i);
            }
            System.out.println();
    
            // 有序
            System.out.print("pool:");
            while (!queue.isEmpty()) {
                System.out.printf(" %d", queue.poll());
            }
            System.out.println();
        }
    }

    可以看到遍历PriorityQueue得到的并不是有序序列, 因为PriorityQueue内部并不是一个按照顺序排序的数组, 而是一个二叉堆(详细可以参考[1. PriorityQueue源码解析, 2. 堆与堆排序 ]).

    由于需要排序,PriorityQueue不允许插入null;

    PriorityQueue的元素有两种排序方式

    • 自然排序: 采用自然排序的元素必须实现了Comparable接口.
    • 定制排序: 创建PriorityQueue时,传入一个Comparator实例,该对象负责对元素进行排序,采用定制排序时不要求队列元素实现Comparable接口.

    关于两种排序的详细内容可以参考下面关于TreeMap的讨论.


    Deque-ArrayDeque

    Deque接口代表一个双端队列,提供了如下方法从队列的两端存取数据:

    Java为Deque提供了两个实现类ArrayDeque(基于数组)与LinkedList(基于链表);由于ArrayDeque底层基于数组E[] elements实现,因此创建时可以指定一个numElements参数设置elements数组初始长度,如果不指定numElements参数,默认数组长度为16(关于ArrayDeque的实现原理可参考ArrayDeque源码解析).

    Deque还可以作为栈stack使用, 他提供了如下方法:

    @Test
    public void asStack() {
        Deque<Integer> stack = new ArrayDeque<>();
    
        for (int i = 0; i < 10; ++i) {
            stack.push(i);
        }
    
        while (!stack.isEmpty()) {
            System.out.println(stack.pop());
        }
    }

    此外, LinkedList也实现了Deque接口,因此也可以作为Queue/Deque的实现类.


    Map

    Map用于保存具有映射关系的key-value数据,keyvalue之间存在单向一对一关系,通过指定的key,总能找到唯一确定的value.

    • update相关
      V put(K key, V value)
      void putAll(Map<? extends K,? extends V> m)
      V remove(Object key)
      void clear()

    • select相关
      V get(Object key)
      Set<K> keySet()
      Collection<V> values()
      Set<Map.Entry<K,V>> entrySet()
      boolean containsKey(Object key)
      boolean containsValue(Object value)
      boolean isEmpty()
      int size()

    Map内部定义一个Map.Entry<K,V>接口,封装key-value对,Entry提供如下方法:

    方法描述
    K getKey()Returns the key corresponding to this entry.
    V getValue()Returns the value corresponding to this entry.
    V setValue(V value)Replaces the value corresponding to this entry with the specified value (optional operation).

    HashMap

    HashMap是基于hash算法的Map实现(用它代替Hashtable),针对key-value的插入/检索,这种形式具有最稳定的性能(O(1)),还可通过构造器对这一性能进行调整.
    为了成功在HashMap中存取数据,key对象必须实现hashCode()equals()方法,HashMap先通过keyhashCode()定位到元素所在桶,如果两个元素在同一个桶,再用equals()进行判断是否相等.如果两个对象的hashCode()相同,但equals()不同, 则将两个对象放在同一个的不同链表位置(这样会导致hash效率下降).如果两个对象通过equals()返回true, 但这hashCode()不同,则非常有可能导致HashMap将这两个对象分配在不同桶中,从而使这两个对象都添加成功,这就与Map规则冲突了.(关于HashMap详细原理可以参考: [1. 哈希表的设计与实现, 2.HashMap源码解析]).

    建议: 如果两个对象通过equals()方法比较返回true, 则两个对象的hashCode()值也相同.

    hashCode()重写规则:

    • 运行过程中, 同一个对象多次调用hashCode()应具有相同返回值;
    • 当两个对象通过equals()比较返回true时, hashCode()应具有相同返回值;
    • 对象中用作equals()比较标准的实例变量, 都应该用于计算hashCode().
    hashCode()重写方法:
    将每个有意义的实例变量都计算出一个 inthashcode值.
    类型计算方式
    booleanhashCode = (true ? 1 : 0);
    floathashCode = Float.floatToIntBits(f);
    doublelong value = Double.doubleToLongBits(f);
    hashCode = (int)(value^(value>>>32));
    int/short/bytehashCode = (int)i;
    longhashCode = (int)(l^(l>>>32));
    引用类型hashCode = object.hashCode();
    用上面计算出来的多个 hashcode组合计算成一个最终的 hashcode,为了避免直接相加产生偶然相等,可以为各个 hashcode乘以任意一个质数再相加:
    • String实现
    public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;
    
            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }

    StringhashCode()方法做了一些优化, 叫闪存散列码, 详见数据结构与算法分析 : Java语言描述

    • 自定义Bean
    /**
     * @author jifang
     * @since 16/1/13下午7:50.
     */
    public class Bean implements Serializable {
    
        private static final long serialVersionUID = 2975296536292876992L;
    
        private boolean isUsed;
    
        private double rate;
    
        private String name;
    
        @Override
        public int hashCode() {
            long rateHash = Double.doubleToLongBits(rate);
            int isUsedHash = isUsed ? 1 : 0;
            int nameHash = name.hashCode();
    
            return nameHash * 11 + (int) (rateHash ^ (rateHash >>> 32)) * 13 + isUsedHash;
        }
    
        // ..
    
    }
    • HashMap的主要实现逻辑:
    /**
     * Associates the specified value with the specified key in this map.
     * If the map previously contained a mapping for the key, the old
     * value is replaced.
     *
     * @param key key with which the specified value is to be associated
     * @param value value to be associated with the specified key
     * @return the previous value associated with <tt>key</tt>, or
     *         <tt>null</tt> if there was no mapping for <tt>key</tt>.
     *         (A <tt>null</tt> return can also indicate that the map
     *         previously associated <tt>null</tt> with <tt>key</tt>.)
     */
    public V put(K key, V value) {
        if (table == EMPTY_TABLE) {
            inflateTable(threshold);
        }
        if (key == null)
            return putForNullKey(value);
        int hash = hash(key);
        int i = indexFor(hash, table.length);
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }
    
        modCount++;
        addEntry(hash, key, value, i);
        return null;
    }
    /**
     * Adds a new entry with the specified key, value and hash code to
     * the specified bucket.  It is the responsibility of this
     * method to resize the table if appropriate.
     *
     * Subclass overrides this to alter the behavior of put method.
     */
    void addEntry(int hash, K key, V value, int bucketIndex) {
        if ((size >= threshold) && (null != table[bucketIndex])) {
            resize(2 * table.length);
            hash = (null != key) ? hash(key) : 0;
            bucketIndex = indexFor(hash, table.length);
        }
    
        createEntry(hash, key, value, bucketIndex);
    }
    
    /**
     * Like addEntry except that this version is used when creating entries
     * as part of Map construction or "pseudo-construction" (cloning,
     * deserialization).  This version needn't worry about resizing the table.
     *
     * Subclass overrides this to alter the behavior of HashMap(Map),
     * clone, and readObject.
     */
    void createEntry(int hash, K key, V value, int bucketIndex) {
        Entry<K,V> e = table[bucketIndex];
        table[bucketIndex] = new Entry<>(hash, key, value, e);
        size++;
    }

    注意

    • 当向Map类容器(如HashMap TreeMap 或后面的HashSet TreeSet)中添加可变对象时,必须十分小心,如果修改Map中的key,有可能导致该key与集合中的其他key相等,从而导致无法准确访问该key-value.因此尽量不要使用可变对象作为Mapkey,或不要修改作为key的对象(Setvalue于此类同)
    • Map还支持containsValue()方法来判断一个value是否存在于Map中, 但该方法会遍历所有的桶查找这个值, 因此性能较差, 不推荐使用
    public boolean containsValue(Object value) {
        if (value == null)
            return containsNullValue();
    
        Entry[] tab = table;
        for (int i = 0; i < tab.length ; i++)
            for (Entry e = tab[i] ; e != null ; e = e.next)
                if (value.equals(e.value))
                    return true;
        return false;
    }
    
    /**
     * Special-case code for containsValue with null argument
     */
    private boolean containsNullValue() {
        Entry[] tab = table;
        for (int i = 0; i < tab.length ; i++)
            for (Entry e = tab[i] ; e != null ; e = e.next)
                if (e.value == null)
                    return true;
        return false;
    }

    LinkedHashMap

    LinkedHashMap使用双向链表来维护key-value插入顺序,因此性能略低于HashMap,但在需要顺序迭代Map的场景下会有非常好的效率.

    LinkedHashMap提供的addEntry()方法与HashMap有所不同,当使用LinkedHashMapput()时, 会从HashMap调回到LinkedHashMapaddEntry()方法,将新元素添加到链表尾:

    /**
     * This override alters behavior of superclass put method. It causes newly
     * allocated entry to get inserted at the end of the linked list and
     * removes the eldest entry if appropriate.
     */
    void addEntry(int hash, K key, V value, int bucketIndex) {
        super.addEntry(hash, key, value, bucketIndex);
    
        // Remove eldest entry if instructed
        Entry<K,V> eldest = header.after;
        if (removeEldestEntry(eldest)) {
            removeEntryForKey(eldest.key);
        }
    }
    
    /**
     * This override differs from addEntry in that it doesn't resize the
     * table or remove the eldest entry.
     */
    void createEntry(int hash, K key, V value, int bucketIndex) {
        HashMap.Entry<K,V> old = table[bucketIndex];
        Entry<K,V> e = new Entry<>(hash, key, value, old);
        table[bucketIndex] = e;
        e.addBefore(header);
        size++;
    }
    • 使用LinkedHashMap统计word出现次数
    /**
     * @author jifang
     * @since 16/1/28 上午10:33.
     */
    public class MapClient {
    
        private Random random = new Random();
    
        @Test
        public void clientLinkedHashMap() {
            Map<String, Integer> map = new LinkedHashMap<>();
            System.out.print("insert key:");
            for (int i = 0; i < 20; ++i) {
                String key = String.valueOf(random.nextInt(10));
                System.out.printf(" %s", key);
                if (map.get(key) == null) {
                    map.put(key, 1);
                } else {
                    map.put(key, map.get(key) + 1);
                }
            }
            System.out.printf("%n iterator:");
    
            for (Map.Entry<String, Integer> entry : map.entrySet()) {
                System.out.printf(" <%s -> %s>", entry.getKey(), entry.getValue());
            }
    
        }
    }

    WeakHashMap

    WeakHashMapHashMap的区别在于:HashMapkey保留了对实际对象的强引用, 这意味着只要该HashMap不被销毁,则Map的所有key所引用的对象不会被垃圾回收;但WeakHashMapkey只保留对实际对象的弱引用, 这意味着如果该key所引用的对象没有被其他强引用变量引用,则该对象可能被垃圾回收,WeakHashMap也会自动删除这些key对应的key-value对.

    @Test
    public void clientWeakHashMap() {
        Map<String, String> map = new WeakHashMap<>();
        String key = "key";
        map.put(key, "value");
        map.put(new String("key1"), "value");
        map.put(new String("key2"), "value");
        System.out.printf("Before : %d%n", map.size());
    
        System.gc();
        System.runFinalization();
        System.out.printf("After : %d ", map.size());
    }

    如果使用WeakHashMap来保留对象的弱引用,则不要让该key所引用的对象具有任何强引用, 否则将失去使用WeakHashMap的意义.


    IdentityHashMap

    HashMap不同,IdentityHashMap判断元素是否相等的标准是用==而不是equals();

    public boolean containsKey(Object key) {
        Object k = maskNull(key);
        Object[] tab = table;
        int len = tab.length;
        int i = hash(k, len);
        while (true) {
            Object item = tab[i];
            if (item == k)
                return true;
            if (item == null)
                return false;
            i = nextKeyIndex(i, len);
        }
    }

    SortedMap-TreeMap

    Map接口派生出SortedMap接口代表根据key排序的key-value集合, TreeMap作为SortedMap的实现类是一个红黑树结构,每个key-value作为红黑树的一个节点.TreeMap存储key-value时,根据key值进行排序.因此TreeMap可以保证所有元素都处于有序状态,因此SortedMapMap的基础上又添加了如下方法:

    方法描述
    Comparator<? super K> comparator()Returns the comparator used to order the keys in this map, or null if this map uses the natural ordering of its keys.
    K firstKey()Returns the first (lowest) key currently in this map.
    K lastKey()Returns the last (highest) key currently in this map.
    SortedMap<K,V> headMap(K toKey)Returns a view of the portion of this map whose keys are strictly less than toKey.
    SortedMap<K,V> tailMap(K fromKey)Returns a view of the portion of this map whose keys are greater than or equal to fromKey.
    SortedMap<K,V> subMap(K fromKey, K toKey)Returns a view of the portion of this map whose keys range from fromKey, inclusive, to toKey, exclusive.

    TreeMap又在SortedMap的基础上扩展了如下方法:

    方法描述
    Map.Entry<K,V> ceilingEntry(K key)Returns a key-value mapping associated with the least key greater than or equal to the given key, or null if there is no such key.
    K ceilingKey(K key)Returns the least key greater than or equal to the given key, or null if there is no such key.
    Map.Entry<K,V> floorEntry(K key)Returns a key-value mapping associated with the greatest key less than or equal to the given key, or null if there is no such key.
    K floorKey(K key)Returns the greatest key less than or equal to the given key, or null if there is no such key.
    Map.Entry<K,V> higherEntry(K key)Returns a key-value mapping associated with the least key strictly greater than the given key, or null if there is no such key.
    K higherKey(K key)Returns the least key strictly greater than the given key, or null if there is no such key.
    Map.Entry<K,V> lowerEntry(K key)Returns a key-value mapping associated with the greatest key strictly less than the given key, or null if there is no such key.
    K lowerKey(K key)Returns the greatest key strictly less than the given key, or null if there is no such key.
    Map.Entry<K,V> pollFirstEntry()Removes and returns a key-value mapping associated with the least key in this map, or null if the map is empty.
    Map.Entry<K,V> pollLastEntry()Removes and returns a key-value mapping associated with the greatest key in this map, or null if the map is empty.
    Map.Entry<K,V> firstEntry()Returns a key-value mapping associated with the least key in this map, or null if the map is empty.
    Map.Entry<K,V> lastEntry()Returns a key-value mapping associated with the greatest key in this map, or null if the map is empty.

    TreeMap有两种排序方式:


    自然排序

    TreeMap的所有key必须实现Comparable接口,TreeMap会调用keyint compareTo(T o);方法来比较元素的大小,然后将集合元素升序排列.

    /**
     * Compares two keys using the correct comparison method for this TreeMap.
     */
    final int compare(Object k1, Object k2) {
        return comparator==null ? ((Comparable<? super K>)k1).compareTo((K)k2)
            : comparator.compare((K)k1, (K)k2);
    }

    Java提供的java.lang.Comparable接口仅包含一个int compareTo(T o);方法.大部分常用类都实现了该接口(如String, Integer等).

    public int compareTo(String anotherString) {
        int len1 = value.length;
        int len2 = anotherString.value.length;
        int lim = Math.min(len1, len2);
        char v1[] = value;
        char v2[] = anotherString.value;
    
        int k = 0;
        while (k < lim) {
            char c1 = v1[k];
            char c2 = v2[k];
            if (c1 != c2) {
                return c1 - c2;
            }
            k++;
        }
        return len1 - len2;
    }

    HashMap不同,TreeMap判断两个key是否相等的唯一标准是:通过compareTo方法比较返回值是否为0.

    public V get(Object key) {
        Entry<K,V> p = getEntry(key);
        return (p==null ? null : p.value);
    }
    
    final Entry<K,V> getEntry(Object key) {
        // Offload comparator-based version for sake of performance
        if (comparator != null)
            return getEntryUsingComparator(key);
        if (key == null)
            throw new NullPointerException();
        Comparable<? super K> k = (Comparable<? super K>) key;
        Entry<K,V> p = root;
        while (p != null) {
            int cmp = k.compareTo(p.key);
            if (cmp < 0)
                p = p.left;
            else if (cmp > 0)
                p = p.right;
            else
                return p;
        }
        return null;
    }
    • 实现Comparable
    /**
     * @author jifang
     * @since 16/1/13下午7:50.
     */
    public class Bean implements Comparable<Bean> {
    
        private boolean isUsed;
    
        private double rate;
    
        private String name;
    
        public Bean(boolean isUsed, double rate, String name) {
            this.isUsed = isUsed;
            this.rate = rate;
            this.name = name;
        }
    
        @Override
        public int compareTo(Bean anotherBean) {
            double another = (anotherBean.isUsed ? 1 : 0) +
                    anotherBean.rate + anotherBean.name.length();
            double self = (isUsed ? 1 : 0) + rate + name.length();
            return (int) (self - another);
        }
    
        @Override
        public String toString() {
            return "Bean{" +
                    "isUsed=" + isUsed +
                    ", rate=" + rate +
                    ", name='" + name + '\'' +
                    '}';
        }
    }
    @Test
    public void clientSortedMap() {
        // value作为期望的order
        SortedMap<Bean, Integer> map = new TreeMap<>();
        map.put(new Bean(true, 3.14, "true"), 1);
        // 该对象与上面的bean compare会返回0
        map.put(new Bean(false, 3.14, "false"), 1);
        map.put(new Bean(true, 3.14, "false"), 2);
        map.put(new Bean(false, 3.14, "true"), 0);
        System.out.println(map);
    
        Bean firstKey = map.firstKey();
        System.out.printf("first: %s -> %d%n", firstKey, map.get(firstKey));
        Bean lastKey = map.lastKey();
        System.out.printf("last: %s -> %d%n", lastKey, map.get(lastKey));
    
        map.remove(firstKey);
        Map.Entry<Bean, Integer> firstEntry = ((TreeMap<Bean, Integer>) map).firstEntry();
        System.out.printf("A first: %s -> %d%n", firstEntry.getKey(), firstEntry.getValue());
    }

    当执行了remove方法后, TreeMap会对集合中的元素重新索引, 这一点可以在调试时看到.


    自定义排序

    TreeMap默认的是使用升序排序,如果需要自定义排序规则,需要为其传入一个Comparator实例, 采用定制排序时不要求key实现Comparable.

    public class MapClient {
    
        private Comparator<Bean> comparator = new Comparator<Bean>() {
            @Override
            public int compare(Bean o1, Bean o2) {
                // 返回正数: 说明o1 > o2
                // 返回负数: 说明o1 < o2
                return -o1.compareTo(o2);
            }
        };
    
        @Test
        public void clientSortedMap() {
            SortedMap<Bean, Integer> map = new TreeMap<>(comparator);
            // ...
        }
    }

    由于TreeMap是基于红黑树实现,因此相比HashMap性能要慢一点(Hash平均O(1),Tree平均O(lgN)详细可参考[1. TreeMap源码解析, 2.红黑树的设计与实现(上)]),但其中的key-value已是有序状态,无需再有专门的排序操作.因此适用于key有序的场景.


    EnumMap

    EnumMap是一个需要与枚举类一起使用的Map,其所有key都必须是单个枚举类的枚举值.EnumMap具有以下特征:

    • EnumMap内部以数组形式存储,紧凑/高效,是Map所有实现中性能最好的.
    • EnumMap根据key的自然顺序(枚举值在枚举类的定义顺序)来维护key-value顺序.
    • EnumMap不允许keynull, 但允许使用null作为value.
    /**
     * @author jifang
     * @since 16/1/27 下午4:01.
     */
    public enum ShopListType {
    
        BLACK_LIST(0, "黑名单"),
        WHITE_LIST(1, "白名单"),
        INVITE_LIST(2, "邀请名单"),
        RECOMMEND_WHITE_LIST(3, "推荐白名单"),
        RECOMMEND_BLACK_LIST(4, "推荐黑名单");
    
        private int type;
    
        private String description;
    
        ShopListType(int type, String description) {
            this.type = type;
            this.description = description;
        }
    
        public int getValue() {
            return type;
        }
    
        public String getDescription() {
            return description;
        }
    }
    @Test
    public void clientEnumMap() {
        EnumMap<ShopListType, String> map = new EnumMap<>(ShopListType.class);
        map.put(ShopListType.BLACK_LIST, "黑名单");
        map.put(ShopListType.WHITE_LIST, "白名单");
        System.out.println(map);
    }

    Set

    SetMap关系非常密切, 虽然Map中存放的是key-value, Set中存放的是单个对象, 但从JDK源代码看, Java是先实现了Map,然后包装一个空Object来填充所有的value来实现的Set.

    private transient HashMap<E,Object> map;
    
    // Dummy value to associate with an Object in the backing Map
    private static final Object PRESENT = new Object();
    public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }

    Set继承自Collection, 没有提供额外的方法;


    HashSet

    HashSetSet接口的典型实现,是Set中用的最多的实现.由于HashSet是基于HashMap实现的,因此具有如下特点:

    • 不保证元素的排列顺序;
    • 不能同步,如果有多个线程同步访问/修改HashSet, 需要开发人员自己保证同步;
    • 集合元素值可以为null;

    LinkedHashSet

    由于LinkedHashSet底层是基于LinkedHashMap实现,因此Set可以记录元素的插入顺序,当遍历LinkedHashSet时,将会按照元素的添加顺序来访问集合中的元素:

    /**
     * @author jifang
     * @since 16/1/26 下午2:09.
     */
    public class SetClient {
    
        @Test
        public void clientLinkedHashSet() {
            Set<Integer> set = new LinkedHashSet<>();
            for (int i = 0; i < 10; ++i) {
                set.add(i);
            }
            for (int i = 19; i >= 10; --i) {
                set.add(i);
            }
            System.out.println(set);
        }
    }

    LinkedHashSet的优缺点与LinkedHashMap类似.


    SortedSet-TreeSet

    SortedSet接口继承自Set,Java为SortedSet提供了TreeSet实现,由于SortedSet可以确保集合元素可以处于已排序状态, 因此在Set的基础上又提供了如下方法:

    类型计算方式
    Comparator<? super E> comparator()Returns the comparator used to order the elements in this set, or null if this set uses the natural ordering of its elements.
    E first()Returns the first (lowest) element currently in this set.
    E last()Returns the last (highest) element currently in this set.
    SortedSet<E> tailSet(E fromElement)Returns a view of the portion of this set whose elements are greater than or equal to fromElement.
    SortedSet<E> headSet(E toElement)Returns a view of the portion of this set whose elements are strictly less than toElement.
    SortedSet<E> subSet(E fromElement, E toElement)Returns a view of the portion of this set whose elements range from fromElement, inclusive, to toElement, exclusive.

    TreeSet相比于SortedSet还提供了如下实用方法:

    类型计算方式
    E ceiling(E e)Returns the least element in this set greater than or equal to the given element, or null if there is no such element.
    E floor(E e)Returns the greatest element in this set less than or equal to the given element, or null if there is no such element.
    Iterator<E> descendingIterator()Returns an iterator over the elements in this set in descending order.
    NavigableSet<E> descendingSet()Returns a reverse order view of the elements contained in this set.
    E higher(E e)Returns the least element in this set strictly greater than the given element, or null if there is no such element.
    E lower(E e)Returns the greatest element in this set strictly less than the given element, or null if there is no such element.
    E pollFirst()Retrieves and removes the first (lowest) element, or returns null if this set is empty.
    E pollLast()Retrieves and removes the last (highest) element, or returns null if this set is empty.

    由于TreeSet底层采用TreeMap实现, 因此其性能特点以及排序规则可以参考TreeMap.


    EnumSet

    EnumSet是专门为枚举设计的Set,所有的元素必须是单一枚举类的枚举值.EnumSet也是有序的,以枚举值在Enum类内定义的顺序来排序;由于EnumSet没有暴露任何构造器,因此需要通过他提供的如下static方法来创建EnumSet实例:

    • allOf(Class<E> elementType)
    • complementOf(EnumSet<E> s)
    • copyOf(Collection<E> c)
    • noneOf(Class<E> elementType)
    • of(E first, E... rest)
    • range(E from, E to)
    @Test
    public void clientEnumSet() {
        EnumSet<ShopListType> set1 = EnumSet.allOf(ShopListType.class);
        System.out.println(set1);
    
        EnumSet<ShopListType> set2 = EnumSet.noneOf(ShopListType.class);
        System.out.println(set2);
        set2.add(ShopListType.BLACK_LIST);
    
        System.out.println(set2);
    }

    EnumSet的内部以位向量的形式存储,紧凑/高效,因此EnumSet占用内存小,运行效率高,是Set实现类中性能最好的. 尤其是批量操作(containsAll(), retainAll())时,如果参数也是EnumSet, 则执行效率非常快(详细可参考Java EnumSet工作原理初窥).


    Collections

    Java提供了一个操作List Map Set等集合的工具类Collections, 其提供了大量的工具方法对集合元素进行排序 查找 更新等操作:

    • 排序相关
      sort(List<T> list) sort(List<T> list, Comparator<? super T> c) shuffle(List<?> list) swap(List<?> list, int i, int j) reverse(List<?> list) reverseOrder(Comparator<T> cmp) rotate(List<?> list, int distance)

    • 查找相关
      binarySearch(List<? extends Comparable<? super T>> list, T key) binarySearch(List<? extends T> list, T key, Comparator<? super T> c) indexOfSubList(List<?> source, List<?> target) lastIndexOfSubList(List<?> source, List<?> target)
      max(Collection<? extends T> coll)
      max(Collection<? extends T> coll, Comparator<? super T> comp)
      min(Collection<? extends T> coll)
      min(Collection<? extends T> coll, Comparator<? super T> comp)

    • 更新相关
      addAll(Collection<? super T> c, T... elements)
      fill(List<? super T> list, T obj)
      nCopies(int n, T o)

    • 不可变集合视图
      unmodifiableCollection(Collection<? extends T> c)
      unmodifiableList(List<? extends T> list)
      unmodifiableMap(Map<? extends K,? extends V> m)
      unmodifiableSet(Set<? extends T> s)
      unmodifiableSortedMap(SortedMap<K,? extends V> m)
      unmodifiableSortedSet(SortedSet<T> s)

    • 单元素集合
      Set<T> singleton(T o)
      singletonList(T o)
      singletonMap(K key, V value)

    • 空集合
      emptyList()
      emptyMap()
      emptySet()
      Collections提供了三个静态变量来代表一个空集合
      static List EMPTY_LIST
      static Map EMPTY_MAP
      static Set EMPTY_SET

    • 同步集合
      详见Java 并发基础


    遗留的集合

    Java还提供了一些集合工具:Hashtable Vactor Stack Enumeration StringTokenizer(Enumeration的一个实现类,其功能类似于Stringsplit(),但不支持正则,实现将字符串进行分割, 然后迭代取出), 这些集合工具都是从Java 1.0开始就存在的, 但其实现要么性能较低(需要保持线程同步), 要么方法名繁琐(如hasMoreElements()), 现在已经很少使用,而且其使用方法也与前面的集合类似, 因此在此就不做过多介绍了. 如果在实际开发中会遇到还在使用这些工具的代码(比如Dom4j),可以参考JDK文档.


    Properties

    PropertiesHashtable的子类,他可以把Map和属性文件关联起来,从而可以把Map对象中的key-value写入属性文件, 也可以将属性文件中的”属性名=属性值”加载到Map中,由于属性文件中的属性名/属性值都是String,因此Propertieskey-value都只能是String.Properties提供了如下方法来读写内存中的key-value.

    方法描述
    String getProperty(String key)Searches for the property with the specified key in this property list.
    String getProperty(String key, String defaultValue)Searches for the property with the specified key in this property list.
    Object setProperty(String key, String value)Calls the Hashtable method put.
    Enumeration<?> propertyNames()Returns an enumeration of all the keys in this property list, including distinct keys in the default property list if a key of the same name has not already been found from the main properties list.
    Set<String> stringPropertyNames()Returns a set of keys in this property list where the key and its corresponding value are strings, including distinct keys in the default property list if a key of the same name has not already been found from the main properties list.

    Properties还提供了读写属性文件的方法:

    方法描述
    void list(PrintStream/PrintWriter out)Prints this property list out to the specified output stream/writer.
    void load(InputStream/Reader in)Reads a property list (key and element pairs) from the input byte/character stream.
    void store(OutputStream/Write out, String comments)Writes this property list (key and element pairs) in this Properties table to the output stream/write in a format suitable for loading into a Properties table using the load(InputStream/Reader) method.
    • common.properties
    dubbo.version=1.0.0
    
    ## Data Source
    mysql.driver.class=com.mysql.jdbc.Driver
    mysql.url=jdbc:mysql://192.168.9.166:3306/common
    mysql.user=admin
    mysql.password=admin
    • client
    @Test
    public void clientProperties() throws IOException {
        Properties properties = new Properties();
        properties.load(ClassLoader.getSystemResourceAsStream("common.properties"));
        System.out.println(properties.get("mysql.driver.class"));
        properties.put("mysql.user", "root");
        properties.put("mysql.password", "root");
        properties.store(new FileOutputStream("common.properties"), "comment");
    }

    Properties还可以从XML中加载key-value,也可以以XML形式保存,其用法与普通.properties文件类似.


    参考:
    给jdk写注释系列之jdk1.6容器
    grepcode.com
    数据结构与STL系列博客
    oracle.javase.docs.api
    Java编程思想
    疯狂Java讲义
    Google Guava官方教程
    数据结构与算法分析
    展开全文
  • 集合的并、交和差运算。从文件中导入初始文本数据,后缀为.txt。有合理的中文提示,每功能可以设立菜单,根据提示完成相关的功能要求。
  • java集合系列——List集合之ArrayList介绍(二)

    万次阅读 多人点赞 2017-02-26 16:06:10
    List是 java.util包下面的类,从 java集合系列——java集合概述(一) 中可以知道,List继承了Collection 接口!...List本身也是一个接口,它的实现有ArrayList 、LinkedList、Vector和CopyOnWriteArrayList等!

    一:List概述
    List是 java.util包下面的类,从 java集合系列——java集合概述(一) 中可以知道,List继承了Collection 接口!
    List本身也是一个接口,它的实现有ArrayList 、LinkedList、Vector和CopyOnWriteArrayList等!
    下面总结分析ArrayList核心的概念和实现原理!

    二:List的几个实现类ArrayList类分析我分析的是jdk1.7.0_79版本
    1:ArrayList的简介

    • ArrayList基于数组实现,是一个动态的数组队列。但是它和Java中的数组又不一样,它的容量可以自动增长,类似于C语言中动态申请内存,动态增长内存!
    • ArrayList继承了AbstractList,实现了RandomAccess、Cloneable和Serializable接口!
    public class ArrayList<E> extends AbstractList<E>
            implements List<E>, RandomAccess, Cloneable, java.io.Serializable
    • 集成了AbstractList,AbstractList又继承了AbstractCollection实现了List接口,它是一个数组队列,提供了相关的添加、删除、修改、遍历等功能!
    public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
        /**
         * Sole constructor.  (For invocation by subclass constructors, typically
         * implicit.)
         */
        protected AbstractList() {
        }
    • 实现了RandomAccess接口,提供了随机访问功能,实际上就是通过下标序号进行快速访问。
    • 实现了Cloneable接口,即覆盖了函数clone(),能被克隆。
    • 实现了Serializable接口,支持序列化,也就意味了ArrayList能够通过序列化传输。

    2: ArrayList的继承关系
    ArrayLList API

    java.lang.Object 
        java.util.AbstractCollection<E> 
            java.util.AbstractList<E> 
                java.util.ArrayList<E> 
    
    All Implemented Interfaces: 
    Serializable, Cloneable, Iterable<E>, Collection<E>, List<E>, RandomAccess 
    Direct Known Subclasses: 
    AttributeList, RoleList, RoleUnresolvedList 

    这里写图片描述

    3:ArrayList方法(API)

    // Collection中定义的API
    boolean             add(E object)
    boolean             addAll(Collection<? extends E> collection)
    void                clear()
    boolean             contains(Object object)
    boolean             containsAll(Collection<?> collection)
    boolean             equals(Object object)
    int                 hashCode()
    boolean             isEmpty()
    Iterator<E>         iterator()
    boolean             remove(Object object)
    boolean             removeAll(Collection<?> collection)
    boolean             retainAll(Collection<?> collection)
    int                 size()
    <T> T[]             toArray(T[] array)
    Object[]            toArray()
    // AbstractCollection中定义的API
    void                add(int location, E object)
    boolean             addAll(int location, Collection<? extends E> collection)
    E                   get(int location)
    int                 indexOf(Object object)
    int                 lastIndexOf(Object object)
    ListIterator<E>     listIterator(int location)
    ListIterator<E>     listIterator()
    E                   remove(int location)
    E                   set(int location, E object)
    List<E>             subList(int start, int end)
    // ArrayList新增的API
    Object               clone()
    void                 ensureCapacity(int minimumCapacity)
    void                 trimToSize()
    void                 removeRange(int fromIndex, int toIndex)

    4:ArrayList的源码分析

    public class ArrayList<E> extends AbstractList<E>
            implements List<E>, RandomAccess, Cloneable, java.io.Serializable
    {
        private static final long serialVersionUID = 8683452581122892189L;
        //属性
        /**
         * 默认初始容量 = 10
         */
        private static final int DEFAULT_CAPACITY = 10;
    
        /**
         * 用于空实例的共享空数组实例。
         */
        private static final Object[] EMPTY_ELEMENTDATA = {};
    
        /**
         *存储ArrayList的元素的数组缓冲区。
         * ArrayList的容量是该数组缓冲区的长度。 任何
         *空的ArrayList与elementData == EMPTY_ELEMENTDATA将被扩展为
         *添加第一个元素时的DEFAULT_CAPACITY。
         */
        private transient Object[] elementData;//注:被transient关键字修饰的变量不再能被序列化,一个静态变量不管是否被transient修饰,均不能被序列化。
    
        /**
         * ArrayList的大小(它包含的元素数量)。
         *
         * @serial
         */
        private int size;
    
        //构造函数
    
        /**
         * Constructs an empty list with the specified initial capacity.
         * 构造具有指定初始容量的空列表。
         *
         * @param  initialCapacity  the initial capacity of the list
         *         initialCapacity  列表的初始容量
         * @throws IllegalArgumentException if the specified initial capacity
         *         is negative
         *      IllegalArgumentException如果指定的初始容量是负数
         */
        public ArrayList(int initialCapacity) {
            super();
            if (initialCapacity < 0)
                throw new IllegalArgumentException("Illegal Capacity: "+
                                                   initialCapacity);
            this.elementData = new Object[initialCapacity];
        }
    
        /**
         * Constructs an empty list with an initial capacity of ten.
         * 构造一个初始容量为10的空列表。
         */
        public ArrayList() {
            super();
            this.elementData = EMPTY_ELEMENTDATA;
        }
    
        /**
         * Constructs a list containing the elements of the specified
         * collection, in the order they are returned by the collection's
         * iterator.
         * 按照集合的迭代器返回的顺序构造包含指定集合的元素的列表。
         * @param c the collection whose elements are to be placed into this list
         *        c 其元素将被放置到此列表中的集合
         * @throws NullPointerException if the specified collection is null
         *        如果指定的集合为null,则为NullPointerException
         */
        public ArrayList(Collection<? extends E> c) {
            elementData = c.toArray();
            size = elementData.length;
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            // c.toArray可能(不正确)不返回Object [](请参阅6260652)
            if (elementData.getClass() != Object[].class)//判断是否返回Object[].class,若没有返回,则使用Arrays.copyOf 进行转换
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        }
    
        /**
         * Trims the capacity of this <tt>ArrayList</tt> instance to be the
         * list's current size.  An application can use this operation to minimize
         * the storage of an <tt>ArrayList</tt> instance.
         *将此<tt> ArrayList </ tt>实例的容量修改为列表的当前大小。 
         *应用程序可以使用此操作最小化<tt> ArrayList </ tt>实例的存储。
         */
        public void trimToSize() {
            modCount++;//在java.util.AbstractList<E>中定义,用于计算对数组的操作次数
            if (size < elementData.length) {
                elementData = Arrays.copyOf(elementData, size);
            }
        }
    
    
         /**
         * Increases the capacity of this <tt>ArrayList</tt> instance, if
         * necessary, to ensure that it can hold at least the number of elements
         * specified by the minimum capacity argument.
         * 如有必要,增加此<tt> ArrayList </ tt>实例的容量,以确保由最小容量参数指定。
         * @param   minCapacity   the desired minimum capacity
         *          minCapacity   所需的最小容量
         */         
        public void ensureCapacity(int minCapacity) {
            int minExpand = (elementData != EMPTY_ELEMENTDATA)
                // any size if real element table
                ? 0
                // larger than default for empty table. It's already supposed to be at default size.
                // 大于默认值为空表。 它应该是默认大小。
                : DEFAULT_CAPACITY;
    
            if (minCapacity > minExpand) { //minCapacity > minExpand 则设置
                ensureExplicitCapacity(minCapacity);
            }
        }
        //确保集合内部的容量
         private void ensureCapacityInternal(int minCapacity) {
            if (elementData == EMPTY_ELEMENTDATA) {
                minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
            }
    
            ensureExplicitCapacity(minCapacity);
        }
    
        private void ensureExplicitCapacity(int minCapacity) {
            modCount++;
    
            // overflow-conscious code
            if (minCapacity - elementData.length > 0)
                grow(minCapacity);
        }
    
         /**
         * The maximum size of array to allocate.
         * Some VMs reserve some header words in an array.
         * Attempts to allocate larger arrays may result in
         * OutOfMemoryError: Requested array size exceeds VM limit
         *一些虚拟机保留数组中的一些标题字。 
         *尝试分配较大的数组可能会导致OutOfMemoryError:请求的数组大小超过VM限制
         * 注:怕超过VM限制,所以只用 Integer.MAX_VALUE - 8  设置MAX_ARRAY_SIZE的值!
         */
        private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
    
        /**
         * Increases the capacity to ensure that it can hold at least the
         * number of elements specified by the minimum capacity argument.
         * 增加容量以确保它至少可以容纳由最小容量参数指定的元素数。
         * @param minCapacity the desired minimum capacity
         *        minCapacity  所需的最小容量
         */
        private void grow(int minCapacity) {
            // overflow-conscious code 溢出-察觉代码
            int oldCapacity = elementData.length; //旧的容量大小
            int newCapacity = oldCapacity + (oldCapacity >> 1); //oldCapacity >> 1 : >> 右移 相当于 oldCapacity/2
            if (newCapacity - minCapacity < 0)
                newCapacity = minCapacity;
            if (newCapacity - MAX_ARRAY_SIZE > 0)
                newCapacity = hugeCapacity(minCapacity);//看下面的hugeCapacity()方法,数组的最大容量不会超过MAX_ARRAY_SIZE
            // minCapacity is usually close to size, so this is a win:
            // minCapacity通常接近于大小,所以这是一个win:
    
            elementData = Arrays.copyOf(elementData, newCapacity);//复制到一个新的数组
        }
    
         private static int hugeCapacity(int minCapacity) {
            if (minCapacity < 0) // overflow
                throw new OutOfMemoryError();
            return (minCapacity > MAX_ARRAY_SIZE) ?
                Integer.MAX_VALUE :
                MAX_ARRAY_SIZE;
        }
    
        /**
         * Returns the number of elements in this list.
         * 返回此列表中的元素数。获取集合的大小
         *
         * @return the number of elements in this list
         *         此列表中的元素数
         */
        public int size() {
            return size;
        }
    
        /**
         * Returns <tt>true</tt> if this list contains no elements.
         * 判断是否为空,如果集合为没有包含任何元素,返回 true !
         * @return <tt>true</tt> if this list contains no elements
         */
        public boolean isEmpty() {
            return size == 0;
        }
    
        /**
         *如果此列表包含指定的元素,则返回true。 更正式地,
         *当且仅当这个列表包含至少一个元素e使得(o == null?e == *null:o.equals(e))时,
         *返回true。
         * @param o element whose presence in this list is to be tested
         * @return <tt>true</tt> if this list contains the specified element
         */
        public boolean contains(Object o) {
            return indexOf(o) >= 0;
        }
    
        /**
         *返回此列表中指定元素的第一次出现的索引,如果此列表不包含元素,
         *则返回-1。 更正式地,返回最低索引i,使得(o == null?get(i)== null:o.equals(get(i))),
         *或-1,如果没有这样的索引。
         * 
         *返回:此列表中指定元素的第一次出现的索引,如果此列表不包含元素,则为-1
         */
        public int indexOf(Object o) {
            if (o == null) {
                for (int i = 0; i < size; i++)
                    if (elementData[i]==null)
                        return i;
            } else {
                for (int i = 0; i < size; i++)
                    if (o.equals(elementData[i]))
                        return i;
            }
            return -1;
        }
    
        /**
         * 返回此列表中指定元素的最后一次出现的索引,如果此列表不包含元素,
         *则返回-1。 更正式地,返回最高索引i,使得(o == null?get(i)== null:o.equals(get(i))),
         *或-1如果没有这样的索引。
         *
         *返回:此列表中指定元素的最后一次出现的索引,如果此列表不包含元素,则为-1
         */
        public int lastIndexOf(Object o) {
            if (o == null) {
                for (int i = size-1; i >= 0; i--)
                    if (elementData[i]==null)
                        return i;
            } else {
                for (int i = size-1; i >= 0; i--)
                    if (o.equals(elementData[i]))
                        return i;
            }
            return -1;
        }
    
    
        /**
         * Returns a shallow copy of this <tt>ArrayList</tt> instance.  (The
         * elements themselves are not copied.)
         * 返回此<tt> ArrayList </ tt>实例的浅拷贝。 (元素本身不被复制。) 
         * @return a clone of this <tt>ArrayList</tt> instance
         */
        public Object clone() { //实现了Cloneable接口,覆盖了函数clone(),能被克隆。
            try {
                @SuppressWarnings("unchecked")
                    ArrayList<E> v = (ArrayList<E>) super.clone();
                v.elementData = Arrays.copyOf(elementData, size);
                v.modCount = 0;
                return v;
            } catch (CloneNotSupportedException e) {
                // this shouldn't happen, since we are Cloneable
                // 这不应该发生,因为我们是克隆的
                throw new InternalError();
            }
        }
    
         /**
         * 以正确的顺序返回包含此列表中所有元素的数组(从第一个元素到最后一个元素)。
         *
         * <p>This method acts as bridge between array-based and collection-based
         * APIs.
         * 此方法充当基于阵列和基于集合的API之间的桥梁
         * @return an array containing all of the elements in this list in
         *         proper sequence
         * 一个包含正确顺序的列表中所有元素的数组
         */
        public Object[] toArray() {
            return Arrays.copyOf(elementData, size);//使用Arrays工具类
        }
    
        /**
         * Returns the element at the specified position in this list.
         * 返回此列表中指定位置的元素。
         *
         * @param  index index of the element to return
         *      要返回的元素的索引索引
         * @return the element at the specified position in this list
         *      该列表中指定位置的元素
         * @throws IndexOutOfBoundsException {@inheritDoc}
         */
        public E get(int index) {
            rangeCheck(index);
    
            return elementData(index);
        }
    
        /**
         * Replaces the element at the specified position in this list with
         * the specified element.
         * 用指定的元素替换此列表中指定位置处的元素。
         *
         * @param index index of the element to replace
         *       要替换的元素的索引索引
         * @param element element to be stored at the specified position
         *       元素要素存储在指定位置
         * @return the element previously at the specified position
         *       元素先前在指定位置
         * @throws IndexOutOfBoundsException {@inheritDoc}
         */
        public E set(int index, E element) {
            rangeCheck(index);
    
            E oldValue = elementData(index);
            elementData[index] = element;
            return oldValue;
        }
    
        /**
         * Appends the specified element to the end of this list.
         * 将指定的元素追加到此列表的末尾。
         * @param e element to be appended to this list
         * @return <tt>true</tt> (as specified by {@link Collection#add})
         */
        public boolean add(E e) {
            ensureCapacityInternal(size + 1);  // Increments modCount!! 增加modCount!用于判断
            elementData[size++] = e;
            return true;
        }
    
        /**
         * Inserts the specified element at the specified position in this
         * list. Shifts the element currently at that position (if any) and
         * any subsequent elements to the right (adds one to their indices).
         * 在此列表中指定的位置插入指定的元素。 将当前在该位置的元素(如果有)
         * 和任何后续元素向右移(将一个添加到它们的索引)。
         * @param index index at which the specified element is to be inserted
         * @param element element to be inserted
         * @throws IndexOutOfBoundsException {@inheritDoc}
         */
        public void add(int index, E element) {
            rangeCheckForAdd(index);
    
            ensureCapacityInternal(size + 1);  // Increments modCount!!
            System.arraycopy(elementData, index, elementData, index + 1,
                             size - index);
            elementData[index] = element;
            size++;
        }
    
        /**
         * Removes the element at the specified position in this list.
         * Shifts any subsequent elements to the left (subtracts one from their
         * indices).
         * 删除此列表中指定位置的元素。 将任何后续元素向左移(从它们的索引中减去一个)。
         * @param index the index of the element to be removed
         * @return the element that was removed from the list
         * @throws IndexOutOfBoundsException {@inheritDoc}
         */
        public E remove(int index) {
            rangeCheck(index);
    
            modCount++;
            E oldValue = elementData(index);
    
            int numMoved = size - index - 1;
            if (numMoved > 0)
                System.arraycopy(elementData, index+1, elementData, index,
    
        //public static native void arraycopy(Object src,  int  srcPos,
        //                                 Object dest, int destPos,int length); 
        //调用了本地的方法 : 将指定源数组的数组从指定位置开始复制到目标数组的指定位置。
    
            elementData[--size] = null; // clear to let GC do its work 设置为 null ,让gc去回收
    
            return oldValue;
        }
    
        /**
         * Removes the first occurrence of the specified element from this list,
         * if it is present.  If the list does not contain the element, it is
         * unchanged.  More formally, removes the element with the lowest index
         * 从列表中删除指定元素的第一次出现(如果存在)。
         *如果列表不包含元素,则不会更改。 更正式地,删除具有最低索引i的元素,使得(如果这样的元素存在)
         *(o == null?get(i)== *null:o.equals(get(i)))。 *如果此列表包含指定的元素(或等效地,如果此列表作为调用的结果更改),则返回true。
         *
         * @param o element to be removed from this list, if present
         * @return <tt>true</tt> if this list contained the specified element 如果包含返回 true
         */
        public boolean remove(Object o) {
            if (o == null) {
                for (int index = 0; index < size; index++)
                    if (elementData[index] == null) {
                        fastRemove(index);
                        return true;
                    }
            } else {
                for (int index = 0; index < size; index++)
                    if (o.equals(elementData[index])) {
                        fastRemove(index);
                        return true;
                    }
            }
            return false;
        }
    
        /*
         * Private remove method that skips bounds checking and does not
         * return the value removed.
         * 私有删除方法,跳过边界检查,不返回值删除。
         */
        private void fastRemove(int index) {
            modCount++;
            int numMoved = size - index - 1;
            if (numMoved > 0)
                System.arraycopy(elementData, index+1, elementData, index,
                                 numMoved);
            elementData[--size] = null; // clear to let GC do its work
        }
    
        /**
         * Removes all of the elements from this list.  The list will
         * be empty after this call returns.
         *从此列表中删除所有元素。 此调用返回后,列表将为空
         */
        public void clear() {
            modCount++;
    
            // clear to let GC do its work
            for (int i = 0; i < size; i++)
                elementData[i] = null;
    
            size = 0;
        }
    
         /**
         * 将指定集合中的所有元素以指定集合的Iterator返回的顺序追加到此列表的末尾。 *如果在操作正在进行时修改指定的集合,则此操作的行为是未定义的。 *(这意味着如果指定的集合是此列表,则此调用的行为是未定义的,并且此列表不是空的。)
         * @param c collection containing elements to be added to this list
         * @return <tt>true</tt> if this list changed as a result of the call
         * @throws NullPointerException if the specified collection is null
         */
        public boolean addAll(Collection<? extends E> c) {
            Object[] a = c.toArray();
            int numNew = a.length;
            ensureCapacityInternal(size + numNew);  // Increments modCount
            System.arraycopy(a, 0, elementData, size, numNew);
            size += numNew;
            return numNew != 0;
        }
        /*
        *将指定集合中的所有元素插入到此列表中,从指定位置开始。
        *
        */
         public boolean addAll(int index, Collection<? extends E> c) {
            rangeCheckForAdd(index);
    
            Object[] a = c.toArray();
            int numNew = a.length;
            ensureCapacityInternal(size + numNew);  // Increments modCount
    
            int numMoved = size - index;
            if (numMoved > 0)
                System.arraycopy(elementData, index, elementData, index + numNew,
                                 numMoved);
    
            System.arraycopy(a, 0, elementData, index, numNew);
            size += numNew;
            return numNew != 0;
        }
    
        /**
         * Removes from this list all of the elements whose index is between
         * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.
         * Shifts any succeeding elements to the left (reduces their index).
         *从此列表中删除其索引在fromIndex(包含)和toIndex(排除)之间的所有元素。
         *将任何后续元素向左移(减少其索引)。
         */
        protected void removeRange(int fromIndex, int toIndex) {
            modCount++;
            int numMoved = size - toIndex;
            System.arraycopy(elementData, toIndex, elementData, fromIndex,
                             numMoved);
    
            // clear to let GC do its work
            int newSize = size - (toIndex-fromIndex);
            for (int i = newSize; i < size; i++) {
                elementData[i] = null;
            }
            size = newSize;
        }
    
        /**
         * 检查给定的索引是否在范围内。 如果没有,则抛出一个适当的运行时异常。
         * 私有方法
         */
        private void rangeCheck(int index) {
            if (index >= size)
                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
        }
    
        /**
         * A version of rangeCheck used by add and addAll.
         * 由add和addAll使用的rangeCheck的版本。
         * 私有方法
         */
        private void rangeCheckForAdd(int index) {
            if (index > size || index < 0)
                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
        }
    
    
    
    
    
        /**
         * Removes from this list all of its elements that are contained in the
         * specified collection.
         * 从此列表中删除包含在指定集合中的所有元素。
         * @param c collection containing elements to be removed from this list
         * @return {@code true} if this list changed as a result of the call
         * 如果此列表由于调用而更改 则返回true
         */
        public boolean removeAll(Collection<?> c) {
            return batchRemove(c, false);
        }
    
        /**
         * Retains only the elements in this list that are contained in the
         * specified collection.  In other words, removes from this list all
         * of its elements that are not contained in the specified collection.
         *仅保留此列表中包含在指定集合中的元素。 换句话说,
         *从此列表中删除未包含在指定集合中的所有元素。
         * @param c collection containing elements to be retained in this list
         * @return {@code true} if this list changed as a result of the call
         * 如果此列表由于调用而更改 则返回true
         */
        public boolean retainAll(Collection<?> c) {
            return batchRemove(c, true);
        }
        //批量移除
        private boolean batchRemove(Collection<?> c, boolean complement) {
            final Object[] elementData = this.elementData;
            int r = 0, w = 0;
            boolean modified = false;
            try {
                for (; r < size; r++)
                    if (c.contains(elementData[r]) == complement)
                        elementData[w++] = elementData[r];
            } finally {
                // Preserve behavioral compatibility with AbstractCollection,
                // even if c.contains() throws.
                //保留与AbstractCollection的行为兼容性,即使c.contains()抛出。
                if (r != size) {
                    System.arraycopy(elementData, r,
                                     elementData, w,
                                     size - r);
                    w += size - r;
                }
                if (w != size) {
                    // clear to let GC do its work
                    for (int i = w; i < size; i++)
                        elementData[i] = null;
                    modCount += size - w;
                    size = w;
                    modified = true;
                }
            }
            return modified;
        }
    
        /**
         *  将ArrayList实例的状态保存到流(即,序列化它)。
         */
        private void writeObject(java.io.ObjectOutputStream s)
            throws java.io.IOException{
            // Write out element count, and any hidden stuff
            //写出元素数量和任何隐藏的东西
            int expectedModCount = modCount;
            s.defaultWriteObject();
    
            // Write out size as capacity for behavioural compatibility with clone()
            s.writeInt(size);
    
            // Write out all elements in the proper order.
            for (int i=0; i<size; i++) {
                s.writeObject(elementData[i]);
            }
    
            if (modCount != expectedModCount) {
                throw new ConcurrentModificationException();
            }
        }
         /**
         * Reconstitute the <tt>ArrayList</tt> instance from a stream (that is,
         * deserialize it).
         *从流重构 ArrayList 实例(即,反序列化它)。
         */
        private void readObject(java.io.ObjectInputStream s)
            throws java.io.IOException, ClassNotFoundException {
            elementData = EMPTY_ELEMENTDATA;
    
            // Read in size, and any hidden stuff
            //读出元素数量和任何隐藏的东西
            s.defaultReadObject();
    
            // Read in capacity  读入容量
            s.readInt(); // ignored
    
            if (size > 0) {
                // be like clone(), allocate array based upon size not capacity
                ensureCapacityInternal(size);
    
                Object[] a = elementData;
                // Read in all elements in the proper order.
                for (int i=0; i<size; i++) {
                    a[i] = s.readObject();
                }
            }
        }
    
    
         /**
         *对列表中的元素返回一个列表迭代器(以正确的顺序),
         *从列表中指定的位置开始。 指定的索引指示由初始调用返回到next的第一个元素。 
         *对上一个的初始调用将返回具有指定索引减1的元素。
         *  
         *返回的列表迭代器是fail-fast的。
         * @throws IndexOutOfBoundsException {@inheritDoc}
         */
        public ListIterator<E> listIterator(int index) {
            if (index < 0 || index > size)
                throw new IndexOutOfBoundsException("Index: "+index);
            return new ListItr(index);
        }
    
        /**
         * Returns a list iterator over the elements in this list (in proper
         * sequence).
         *返回此列表中的元素(按正确顺序)的列表迭代器。
         * <p>The returned list iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
         *返回的列表迭代器是fail-fast的。
         * @see #listIterator(int)
         */
        public ListIterator<E> listIterator() {
            return new ListItr(0);
        }
    
        /**
         * Returns an iterator over the elements in this list in proper sequence.
         *以正确的顺序返回此列表中的元素的迭代器。
         * <p>The returned iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
         *返回的列表迭代器是fail-fast的。
         * @return an iterator over the elements in this list in proper sequence
         */
        public Iterator<E> iterator() {
            return new Itr();
        }
    
        /**
         * An optimized version of AbstractList.Itr
         * AbstractList.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];
            }
    
            public void remove() {
                if (lastRet < 0)
                    throw new IllegalStateException();
                checkForComodification();
    
                try {
                    ArrayList.this.remove(lastRet);
                    cursor = lastRet;
                    lastRet = -1;
                    expectedModCount = modCount;
                } catch (IndexOutOfBoundsException ex) {
                    throw new ConcurrentModificationException();
                }
            }
    
            final void checkForComodification() {
                if (modCount != expectedModCount)
                    throw new ConcurrentModificationException();
            }
        }
    
        /**
         * An optimized version of AbstractList.ListItr
         * AbstractList.ListItr的优化版本
         */
        private class ListItr extends Itr implements ListIterator<E> {
            ListItr(int index) {
                super();
                cursor = index;
            }
    
            public boolean hasPrevious() {
                return cursor != 0;
            }
    
            public int nextIndex() {
                return cursor;
            }
    
            public int previousIndex() {
                return cursor - 1;
            }
    
            @SuppressWarnings("unchecked")
            public E previous() {
                checkForComodification();
                int i = cursor - 1;
                if (i < 0)
                    throw new NoSuchElementException();
                Object[] elementData = ArrayList.this.elementData;
                if (i >= elementData.length)
                    throw new ConcurrentModificationException();
                cursor = i;
                return (E) elementData[lastRet = i];
            }
    
            public void set(E e) {
                if (lastRet < 0)
                    throw new IllegalStateException();
                checkForComodification();
    
                try {
                    ArrayList.this.set(lastRet, e);
                } catch (IndexOutOfBoundsException ex) {
                    throw new ConcurrentModificationException();
                }
            }
    
            public void add(E e) {
                checkForComodification();
    
                try {
                    int i = cursor;
                    ArrayList.this.add(i, e);
                    cursor = i + 1;
                    lastRet = -1;
                    expectedModCount = modCount;
                } catch (IndexOutOfBoundsException ex) {
                    throw new ConcurrentModificationException();
                }
            }
        }
    
        //subList 以及后面的代码不在做分析,实际情况中很少用到,需要的时候,请自行看源码分析
    }   

    5:总结

    1. ArrayList 本质实现方法是用数组!是非同步的!

    2. 初始化容量 = 10 ,最大容量不会超过 MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8!

    3. indexOf和lastIndexOf 查找元素,若元素不存在,则返回-1!

    4. 当ArrayList容量不足以容纳全部元素时,ArrayList会重新设置容量:新的容量=“(原始容量x3)/2 ”。

    5. ArrayList的克隆函数,即是将全部元素克隆到一个数组中。

    6. ArrayList实现java.io.Serializable的方式。当写入到输出流时,先写入“容量”,再依次写入“每一个元素”;当读出输入流时,先读取“容量”,再依次读取“每一个元素”。

    7. 从代码中可以看出,当容量不够时,每次增加元素,都要将原来的元素拷贝到一个新的数组中,非常之耗时,也因此建议在事先能确定元素数量的情况下,才使用ArrayList,否则建议使用LinkedList。

    8. ArrayList的实现中大量地调用了Arrays.copyof()和System.arraycopy()方法。具体分析见第一篇参考文章

    9. ArrayList基于数组实现,可以通过下标索引直接查找到指定位置的元素,因此查找效率高,但每次插入或删除元素,就要大量地移动元素,插入删除元素的效率低。

    10. 在查找给定元素索引值等的方法中,源码都将该元素的值分为null和不为null两种情况处理,ArrayList中允许元素为null。

    三:参考文章
    http://blog.csdn.net/ns_code/article/details/35568011” target=”_blank”>http://blog.csdn.net/ns_code/article/details/35568011
    http://www.cnblogs.com/skywang12345/p/3308556.html


    java集合系列——java集合概述(一)
    java集合系列——List集合之ArrayList介绍(二)
    java集合系列——List集合之LinkedList介绍(三)
    java集合系列——List集合之Vector介绍(四)
    java集合系列——List集合之Stack介绍(五)
    java集合系列——List集合总结(六)
    java集合系列——Map介绍(七)
    java集合系列——Map之HashMap介绍(八)
    java集合系列——Map之TreeMap介绍(九)
    java集合系列——Set之HashSet和TreeSet介绍(十)



    如果帅气(美丽)、睿智(聪颖),和我一样简单善良的你看到本篇博文中存在问题,请指出,我虚心接受你让我成长的批评,谢谢阅读!
    祝你今天开心愉快!


    欢迎访问我的csdn博客,我们一同成长!

    不管做什么,只要坚持下去就会看到不一样!在路上,不卑不亢!

    博客首页http://blog.csdn.net/u010648555

    展开全文
  • 发现这样的话每次item值都会是list最后一个元素。 解决方法: 把 #{item} 改成 ${item} ps. 改成 ${item} 的话又要考虑sql注入问题,于是最后没有用bind标签,用了 like '%'||#{param}||'%'
  • oracle中like和regexp_like

    千次阅读 2019-05-21 09:48:20
    最近使用oracle中发现连续使用多not like(超过4之后)就查询不出结果,但是也不报错,比如:select * from a not like ‘%1%’ and a not like ‘%2%’ and a not like ‘%3%’ and a not like ‘%4%’ and a ...
  • setfilter 使用两个LIKE 问题

    千次阅读 2012-05-12 10:33:01
    使用如下两个LIKE筛选,得不到想要的结果!!! dw_child.setfilter("name like '%" + data + "%' or ...加上括号就行了,不加括号的话只能用一个like。    dw_child.setfilter("(name like '%" + data + "%'
  • sql.append(" and staff_num like '%'||:staffNum||'%'"); parame.addValue("staffNum", condition.get("staffNum")); } if(condition.containsKey("staffIsLocked")){ sql.append(" and staff_isLocked...
  • 数据库SQL语句 SELECT LIKE like用法详解

    千次阅读 2018-08-06 18:24:17
    LIKE语句的语法格式是:select * from 表名 where 字段名 like 对应值(子串),它主要是针对字符型字段的,它的作用是在一个字符型字段列中检索包含对应子串的。 A:% 包含零个或多个字符的任意字符串: 1、LIKE'...
  • SQL如何判断LIKE(模式匹配)类型?

    千次阅读 2017-01-23 16:36:51
    SQL中可以使用LIKE实现模式匹配,以%作为通配符语法: (1)'keywords%'以keywords...遇到一个需求,不但要找出模式匹配的子集合,还有知道是哪一种匹配,从头开始?尾部匹配?中间匹配? 使用场景是Android Prov
  • 一个小例子集合xlrd,matplotlib,numpy,scipy使用方法(从Excel导入数据)最近因为一篇论文的原因,要从Excel中取得部分数据平作图,但是得到的图都是位图,不是太好插入到论文中,因此,决定使用Python画图来解决...
  • SQL like用法

    千次阅读 2018-01-27 20:41:29
    % 包含零或更多字符的任意字符串。 _(下划线) 任何单个字符。 [ ] 指定范围(例如 [a-f])或集合(例如 [abcdef])内的任何单个字符。 [^] 不在指定范围(例如 [^a - f])或集合(例如 [^abcdef])内的任何...
  • Android Room数据库Like模糊查询

    千次阅读 2020-08-06 22:03:48
    //查询表user中的user_name 包含‘黄’字的user集合 select * from user where user_name like '%黄%' 2、Room中的模糊查询 Room中用||代替+号 示例: // ||相当于+号 @Transaction @Query("SELECT * FROM ...
  • 务实java基础之集合总结

    千次阅读 2017-08-06 11:31:32
    声明:本篇博客内容参考自《java编程思想》,代码均来自书中,大部分内容截取自该书数组和第一类对象无论使用的数组属于什么类型,数组标识符实际都是指向真实对象的一个句柄。那些对象本身是在内存 “堆”里创建的...
  • MySQL SELECT LIKE like的用法

    千次阅读 2011-06-09 20:14:00
    MySQL提供标准的SQL模式匹配,以及种基于象Unix实用程序如vi、grep和sed的扩展正则表达式模式匹配的格式。SQL的模式匹配允许你使用“_”匹配任何单个字符,而“%”匹配任意数目字符(包括零字符)。在 MySQL中,...
  • SQL语句 SELECT LIKE用法详解

    千次阅读 2012-08-30 09:42:45
    LIKE语句的语法格式是:select * from 表名 where 字段名 like 对应值(子串),它主要是针对字符型字段的,它的作用是在一个字符型字段列中检索包含对应子串的。 A:%包含零个或多个字符的任意字符串: 1、...
  • 测试一个对象是否为 String-like 对象Credit: Luther Blissett 问题您需要一个对象(通常会作为实参用于您正在撰写的方法或函数)进行检测,查看其是否为字符串(更准确地说,是否为 string-like 对象)。...
  • vb like的用法

    千次阅读 2011-02-19 10:43:00
    另外,通过使用左括号和右括号([、]),你可以指定一个用来匹配的字符集合。 <br />  下面的代码给出了几种可以使用Like运算符的方法。 <br /> If "(800) 555-5555" Like "(###) #
  • 控制台打印sql语句如下: SELECT * FROM SRM_MDM_SUPPLIER_ALL WHERE DISABLED = 0 AND EMPLOYEE_CODE = '03426' AND (VENDOR_FULL_NAME LIKE '%1183%' OR VENDOR_CODE LIKE '%1183%' OR VENDOR_ID LIKE '%1183%')
  • SQL Like通配符

    千次阅读 2011-07-07 10:23:48
    半角单引号 示例:查询备注字段包含半角单引号的所有学生信息。 select * from Students where desp like '%'...其中,第一个'意即转义,第二个'意即真正的半角单引号。   LIKE通配符 确定给定的字符串是否与指定
  • spark-sql like查询

    千次阅读 2017-08-27 14:53:47
    当时遇到使用两表,需要用到like的时候,建议使用map side join或者使用spark sql的broad cast joinsqlContext.sql( """ |select * from left A,right B where A.url like contact(B.url,'%') """.stripMargin)...
  • .通过Matcher中的find()方法对list集合进行模糊查询操作 1.创建实体对象: public class User { private Integer id; private String name; private String password; public User() { } public User...
  • oracle集合运算

    2012-03-14 23:41:34
    oracle集合运算 一 介绍  1.集合运算符包括并集(union/union all),交集(intersect),差集(minus).  2.并集:union运算符返回两个集合去掉重复元素后的所有记录。...4.差集:minus返回属于第一个集合
  •  、一般搜索条件中用Like  可与LIKE配对的数据类型主要是字符串、日期或时间值。LIKE 关键字可以使用常规表达式包含上面三种类型数据,这些数据字符串中可包含下面四种通配符的任意组合。  通配符 含义  % ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 149,233
精华内容 59,693
关键字:

like一个集合