JAVA基础——集合

2023-10-30


前言

此篇为记录Java基础中集合章节的有关知识点,主要包括Collection接口、Map接口下的实现类,以及他们之间的联系和区别


一、集合概要及框架体系

1、集合的理解

  • 集合跟数组一样,它也是用来保存数据的。那么为什么还会出现集合呢?那是因为数组有许多不足的地方。集合主要是两组(单列集合、双列集合)

2、数组的缺点

  • 长度开始时必须指定,而且一旦指定,不能更改。
  • 保存的数据类型必须为同一类型的元素。
  • 使用数组进行增加/删除元素时比较麻烦(每次都要进行扩容或者缩减)

3、集合的好处

  • 可以动态保存任意类型的对象或元素,使用方便
  • 提供一系列的操作对象的方法,不用自己实现它,可以直接使用,进行添加删除新元素方便。

4、集合的框架体系

1、Java的集合类很多,主要有Collection 接口和 Map 接口两大类,它们都继承了 Iterable 接口。
2、Collection接口 最常见的是Set 和List 接口;

  • Set接口中的常用实现类有:HashSet、TreeSet
  • List接口中的常用实现类有:ArrayList 、LinkedList、Vector,其中Vector的子类有常见的Stack(栈)类

3、Map接口中常见的实现类有HashMap、TreeMap、HashTable

  • HashMap常用的继承子类有LinkedHashMap
  • HashTable常用的继承子类有Properties

集合框架思维导图

二、Collection集合(单列集合)

Collection集合特点

  • Collection 实现子类可以存放多个元素,每个元素可以是Object
  • 有些Collection的实现类可以存放重复的元素,有些不可以
  • 有些Collection 的实现类是有序的(List),有些不是有序(Set)
  • Collection接口没有直接实现的子类,是通过它的子接口List和Set来实现的

Collection集合遍历元素方式

1、迭代器的遍历方式

//以hashSet为例:
        HashSet hashSet = new HashSet();
        Iterator iterator = hashSet.iterator();//1. 先得到 col 对应的 迭代器
        //使用 while 循环遍历,此循环可以使用 itit 快捷键
        //显示所有的快捷键的的快捷键 ctrl + j
        while (iterator.hasNext()) {//判断是否还有数据
            Object obj =  iterator.next();//返回下一个元素,类型是 Object
            System.out.println(obj);
        }
//当退出 while 循环后 , 这时 iterator 迭代器,指向最后的元素 iterator.next();
//NoSuchElementException 
//如果希望再次遍历,需要重置我们的迭代器 
iterator = hashSet.iterator();

注意:

  • 多次使用此迭代器时需要重置一下,因为每次循环完之后迭代器的
  • 在调用iterator.next()方法之前必须要调用iterator.hasNext()进行检测。若不调用,且下一条记录无效,直接调用it.next()会抛出NoSuchElementException异常。

2、增强for循环的遍历方式

//以HashSet为例
HashSet hashSet = new HashSet();
 for (Object obj : hashSet) {//此时可用快捷键 hashSet.I
            System.out.println(obj);
        }

1、List

List 接口是Collection接口的子接口。

  1. List集合内的元素是有序的(添加顺序和取出顺序一致)、且可以重复。
  2. List集合的每个元素都有其对应的顺序索引,即支持索引
  3. List容器中的元素是都对应一个整数型的序号记载其在容器的位置

Ⅰ. ArrayList底层结构和源码分析

一、注意事项

  1. ArrayList底层是由数组实现数据存储的。
  2. ArrayList基本等同于Vector,除了ArrayList是线程不安全的(执行效率高),而Vertor是线程安全的。不建议使用ArrayList.

二、底层操作机制源码分析
扩容机制结论:

  1. ArrayList 底层维护了一个Object类型的数组elementData。

  2. 当创建ArrayList对象时它有两种构造器,一种是无参构造,另一种是有参构造。当它创建时的长度为0时使用无参构造,则扩容elementData为10,如需要再次扩容,则是elementData的1.5倍。

  3. 当创建elementData给定一个长度时用有参构造,如需要扩容,则直接扩容为elementData的1.5倍。

  4. 在添加元素的时候,先调用特定的方法来确定是否要扩容(每次都要看是否需要扩容)

 public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

确定要扩容之后把需要扩容的大小设置为10,然后表示扩容的次数的变量自增1,如果大小不够,就调用grow()扩容(扩容到原来的1.5倍(length + length >> 1)),容量够了就不会调用grow()方法了。

private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }

    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

grow()方法源码:

 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);
    }

Ⅱ Vector 底层结构和源码分析

一、注意事项

  • Vector集合跟ArrayList底层大致相同,只不过Vector跟ArrayList相比,它的线程安全(synchronized)
  • 它的扩容机制也跟ArrayList类似,在扩容时如果是没有给定大小,那么第一次扩容为10,但是第二次开始是按2倍扩容。
  • 与ArrayList相比,它的线程安全,但执行效率稍低。

二、debug源码

//底层同样跟ArrayList是elementData数组
public synchronized boolean add(E e) {
        modCount++;
        ensureCapacityHelper(elementCount + 1);
        elementData[elementCount++] = e;
        return true;
    }
private void ensureCapacityHelper(int minCapacity) {
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
 private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        /**二倍扩容机制
		*/
        int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                         capacityIncrement : oldCapacity);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
Vector子类——Stack(栈)

Ⅲ LinkedList底层结构和源码分析

一、注意事项

  • LinkedList中维护了两个属性,first和last ,first指向第一个节点Node,Last指向最后一个节点Node。
  • 每个Node节点中有prev(指向前一个节点)、next(指向下一个节点)、item(内容)这三个属性,最终实现双向链表
  • LinkedList底层维护了一个双向链表,而不是数组,所以添加和删除效率比ArrayList和Vector都高。

二、DebugLinkedList的添加元素 源代码

//DebugLinkedList的添加元素 源代码
 public boolean add(E e) {
       linkLast(e);
       return true;
   }
 void linkLast(E e) {
       final Node<E> l = last;
       final Node<E> newNode = new Node<>(l, e, null);
       last = newNode;
       if (l == null)
           first = newNode;
       else
           l.next = newNode;
       size++;
       modCount++;
   }
    private static class Node<E> {
       E item;
       Node<E> next;
       Node<E> prev;

       Node(Node<E> prev, E element, Node<E> next) {
           this.item = element;
           this.next = next;
           this.prev = prev;
       }
   }

三、DebugLinkedList的插入元素 源代码

public void add(int index, E element) {
      checkPositionIndex(index);

      if (index == size)
          linkLast(element);
      else
          linkBefore(element, node(index));
  }
    /**
   * Inserts element e before non-null Node succ.
   */
  void linkBefore(E e, Node<E> succ) {
      // assert succ != null;
      final Node<E> pred = succ.prev;
      final Node<E> newNode = new Node<>(pred, e, succ);
      succ.prev = newNode;
      if (pred == null)
          first = newNode;
      else
          pred.next = newNode;
      size++;
      modCount++;
  }
   private static class Node<E> {
     E item;
     Node<E> next;
     Node<E> prev;

     Node(Node<E> prev, E element, Node<E> next) {
         this.item = element;
         this.next = next;
         this.prev = prev;
     }
 }

Ⅳ. ArrayList 和 LinkedList 比较

  • ArrayList底层是通过数组实现的,如果使用查改的操作比较多,就选ArrayList。
  • LinkedList底层是通过链表实现的,如果使用增删的操作比较多,就选LinkedList。
  • 一般来说使用改查的操作比较多,大多使用ArrayList;有时会结合使用。

2.Set

一、注意事项

  • Set集合是无序的,因此它没有索引,也就不能通过索引来获取元素,也不能用普通循环通过索引遍历元素(要用迭代器或者增强for循环)。
  • Set集合无序,所以不能存储重复的元素

2.1HashSet

一、注意事项

  • HashSet实现了Set接口
  • HashSet的底层实际上是HashMap(数组+链表+ 红黑树)
  • HashSet不保证元素是有序的。

二、HashSet添加元素的扩容机制

1.HashSet的底层是HashMap,添加一个元素时,先得到它的hash值,然后通过算法转化成索引值。第一次添加时,table数组扩容到16,临界值是12(个元素),到达临界时就会进行第二次扩容(临界值 = 容量 * 0.75),扩容时按两倍容量扩容.
2. 找到存储数据表table(是一个Node类型的数组),看这个索引位置是否已经存放的有元素,如果没有则直接添加;如果有,则调用equals方法比较(equals方法是程序员自己设置的比较方法(重写)),如果相同,则放弃添加,反之则加到最后。
3. 在Java8中,如果一条链表的元素到达8个,并且table的大小达到64个,那么会树化(形成红黑树).如果一条链表达到8个但是table的大小还没到64,则会继续扩容table表,并且在同一条链表上,那么每加一个就会扩容一次(因为都大于8),直到满足table表大于64,才会树化。

三、HashSet的源码解读
1、HashSet底层实际上是HashMap

 public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }

2、底层调用的是HashMap的put()

public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }
    /**
    hash(key)的值是通过hash方法得来的
    而hash方法里又有hashXCode()以及相应的算法(h >>> 16)
    */
    //hash()源码: 
static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }
//hashCode()源码:
  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;
    }

3、关键点在putVal()上:

  1. 先判断数组(table表)是否为空,如果数组为空那么就给数组一个初始值,这个默认值为16
    final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;//这是一些临时变量
        /**
			如果数组为空那么就给数组一个初始值,这个默认值为16
		*/
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
             /**
				判断数组表中的位置是否为空,如果为空,则在数组table表中添加这个新的元素(结点)
					
					*/
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
             /**
				否则就定义一个节点,
				1、如果要添加元素的hash值与p的hash值(当前table表的某个Node,它的链表的头节点位置的hash值)相等
				或者这个要添加元素的key值与当前链表的头结点的key值相等(equals方法是程序员自己重写的,具体通过什么来判断是不确定的)
				那么就把当前结点赋值给e
				2、如果p是一个红黑树的节点,就执行树的添加机制
				
					*/
        else {
            Node<K,V> e; K k;
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
                /**
					3.1否则(不是同一个元素),循环判段table表的这个元素的这个链表,
					如果有相同的就放弃添加,
					如果判断完了没有相同的就加在链表的最后。
					如果链表的长度大于等于8以后,就执行treeifyBin(),也就是会再看table表的长度有没有64(会进入判断是否树化的方法中).
				*/
            else {
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                        break;
                    }
                   
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }
            }
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
        }
        ++modCount;
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }

2.1.1LinkedHashSet

一、注意事项

  1. LinkedHashSet与HashSet类似,只不过LinkedHashSet底层是LinkedHashMap,它维护了一个数组 + 双向链表。
  2. 这个双向链表通过Before 和after属性形成的。
  3. 这个双向链表串起来所有的元素(相当于数组每个位置都能有一个双向链表,并且与其它位置的链表也是链接在一起的)。
  4. 因为有双向链表,所以看起来存储和取出的顺序一样。
  5. 它同样不允许添加重复的元素(怎么算重复也是自己可以重写hashCode() 和equals() 来决定)

二、底层源码分析

  1. 通过创建一个LinkedHashSet对象,然后往里面添加元素,可以发现,第一次拿到对象添加元素时便将table扩容到16了。
  2. map里有一个head头结点和tail尾节点,

在这里插入图片描述
3. table是一个多态数组,它的编译类型是Node,但是里面存放的是Entry,说明Entry继承了Node(事实上他们都是内部类,Entey内部类也确实继承了Node内部类)
在这里插入图片描述

/**
    * HashMap.Node subclass for normal LinkedHashMap entries.
    */
   static class Entry<K,V> extends HashMap.Node<K,V> {
       Entry<K,V> before, after;
       Entry(int hash, K key, V value, Node<K,V> next) {
           super(hash, key, value, next);
       }
   }```

```java

2.2TreeSet

一、注意事项

  1. TreeSet的底层是TreeMap,它能实现排序是因为有一个内部类方法(comparetor),这个comparetor的排序规则可以自己更改(例如:当添加元素时,可以认为长度相等就是相等的元素,就会添加不进去)
 TreeSet treeSet = new TreeSet(new Comparator() {
           @Override
           public int compare(Object o1, Object o2) {
               //按照K(string)的大小进行排序
               return ((String)o1).compareTo((String)o2);
               //也可按照K(string)的长度进行排序
               //return ((String)o1).length - ((String)o2).length;
           }
       });

二、源码分析(以添加元素为例)
在add时底层也是调用put()

public boolean add(E e) {
       return m.put(e, PRESENT)==null;
   }

//而关键就在于put(),它里面有一个compare方法,用来判断两个Key是否相等,然后执行相应的添加机制。

    public V put(K key, V value) {
        Entry<K,V> t = root;
        if (t == null) {
            compare(key, key); // type (and possibly null) check

            root = new Entry<>(key, value, null);
            size = 1;
            modCount++;
            return null;
        }
        int cmp;
        Entry<K,V> parent;
        // split comparator and comparable paths
        Comparator<? super K> cpr = comparator;
        if (cpr != null) {
            do {
                parent = t;
                cmp = cpr.compare(key, t.key);
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else
                    return t.setValue(value);
            } while (t != null);
        }
        else {
            if (key == null)
                throw new NullPointerException();
            @SuppressWarnings("unchecked")
                Comparable<? super K> k = (Comparable<? super K>) key;
            do {
                parent = t;
                cmp = k.compareTo(t.key);
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else
                    return t.setValue(value);
            } while (t != null);
        }
        Entry<K,V> e = new Entry<>(key, value, parent);
        if (cmp < 0)
            parent.left = e;
        else
            parent.right = e;
        fixAfterInsertion(e);
        size++;
        modCount++;
        return null;
    }


    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;
    }


三、Map集合(双列集合)

一、注意事项

  1. Map集合跟Collection集合是并列关系,它与Collection集合不同的是,它是双列集合(K-V形式存放数据)。
  2. Map的Key值不允许重复(只能有一个NULL值),但是Value可以重复。并且它们的类型可以是任意值,但是常用String来作为Key的类型。
  3. Map集合中可以通过Key值来找到相对应的Value(支持索引)。

1、HashMap

一、注意事项:

  1. HashMap是Map的实现类中最常用的,它通过K-V键值对的方式来存储数据(HashMap$Node类型)
  2. Key不能重复,但是Value值可以重复或者被替换(添加相同的Key和Value时,key不会被替换,但是Value会被替换)。
  3. HashMap跟HashSet类似,不能保证映射的顺序,因为底层是通过hash表(算法)来决定存储的位置的。
  4. HashMap没有实现同步,因此是线程不安全的,它没有实现synchronized。

二、底层机制

  1. HashMap与HashSet的底层是相同的(HashSet在构造器中创建了一个HashMap对象)。
  2. HashMap在创建时默认为null,它首先初始化一个加载因子为0.75,并且每次扩容都是按2倍,第一次扩容默认为16,临界值为 16*0.75 = 12。
  3. 在添加key-value时,会根据key的hash值来确定它们的存放位置;存放时判断当前的key值与要添加的key值是否相等,相等则替换value;如果不等,看结构是链表还是树结构,如果是链表结构再判断链表的大小和table的大小来决定是否要树化,(在java8中如果一条链表的长度超过8,并且table大小超过64就会树化)如果是树的结构也会判断equals方法…做相应的处理;如果容量不够则需要扩容。
    三、源码分析(以添加元素为例)
    1、在创建对象时,构造器里会先初始化一个加载因子,它的值为0.75.
 public HashMap() {
        this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
    }

2、添加时调用put()方法,里面实际上是一个putVal() 和一个hash算法(hash(key)是为了得到key对应得hash值,以此来确定索引的位置)

public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }

3、详细看代码的注释:

    final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        //这个if是判断当前的table是否为空,如果为空则默认扩容为16
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
        //这里是判断当前hash值对应的索引位置是否为空,如果为空,直接将元素放在这。
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        else {//到这里说明这个hash值对应table的索引位置有元素了,所以要开始进一步判断
            Node<K,V> e; K k;
            //①如果(它们的hash值相等)&&(要存放元素的key与当前的Key相等 || 它们的equals相等)
            //此时相当于用新的元素来替换掉当前元素,当然Key是不变的(key值唯一,替换value值)
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            //②如果当前的元素是一个树结构,那么直接放在树的节点后。
            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            //以上①②都不满足,说明要添加的元素要放的位置是当前链表
            else {
            //循环判断当前链表的所有元素,如果没有相同的,就把它添加到链表最后
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
                        //如果链表的元素 >= TREEIFY_THRESHOLD(8) - 1,
                        //则进入到treeifyBin(判断table的大小有没有64,再决定要不要树化) 
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                        break;
                    }
                    //如果链表中的元素与要添加的元素相同,那么就break。
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }
            }
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
        }
        ++modCount;
        if (++size > threshold)//这是加载因子,如果达到临界值就按2倍扩容
            resize();
        afterNodeInsertion(evict);
        return null;
    }

2、HashTable

一、注意事项

  • HashTable底层有一个数组(HashTable$Node)
  • HashTable 也是通过K-V的方式来存储数据的,并且它的key和value都不能为空。
  • 它是线程安全的,有synchonized处理
  • 它的加载因子也是0.75,初始容量为11,扩容是按2倍加1来扩容的。

二、底层源码

public synchronized V put(K key, V value) {
       // Make sure the value is not null
       if (value == null) {
           throw new NullPointerException();
       }

       // Makes sure the key is not already in the hashtable.
       Entry<?,?> tab[] = table;
       int hash = key.hashCode();
       int index = (hash & 0x7FFFFFFF) % tab.length;
       @SuppressWarnings("unchecked")
       Entry<K,V> entry = (Entry<K,V>)tab[index];
       for(; entry != null ; entry = entry.next) {
           if ((entry.hash == hash) && entry.key.equals(key)) {
               V old = entry.value;
               entry.value = value;
               return old;
           }
       }

       addEntry(hash, key, value, index);
       return null;
   }
2.1 properties

一、注意事项

  • properties继承了HashTable,其存储方式也是k-v,并且key和value的值都不能为null。
  • 如果有相同的kry,那么value的值会被替换。

二、使用入门

public class PropertiesTest {
  public static void main(String[] args) throws Exception {

      Properties properties = new Properties();//1、先创建properties对象
      properties.load(new InputStreamReader(//2、加载配置文件,注意编码格式
              new FileInputStream("src\\mysql.properties"),"GBK"));
      //这里要设置编码,编码格式要与properties的格式一致,这里Properties的编码是GBK,所以也将它设置为GBK
      properties.list(System.out);//可以输出配置文件
      String name = properties.getProperty("name");//也可以根据键值对 取出自己想要的值
      String id = properties.getProperty("id");
      String pwd = properties.getProperty("pwd");
      System.out.println("name = " + name +"\nid = "+ id +"\npwd = "+ pwd);


      Properties properties1 = new Properties();
      properties1.setProperty("基本信息","内容");//设置信息
      properties1.setProperty("姓名","韩顺平");
      properties1.setProperty("年龄","21");
      //将上述内容创建一个目标文件并保存在里面。
      //这里的null是注释,如果有的话,在创建的时候会把注释写在文件上面,一般置空
      properties1.store(new FileWriter("src\\mysql2.properties"),null);
      properties1.list(System.out);




  }
}

3、TreeMap

总结:开发中如何选择这些集合?

一、数据是单列存放的(选择Collection)
1、允许重复(选择List)

  • 查改操作多:ArrayList
  • 增删操作多:LinkedList

2、不允许重复(选择Set)

  • 无序:HashSet
  • 插入和取出顺序一致:LinkedHashSet
  • 排序:TreeSet
    二、数据是双列(k-v)存放的(选择Map)
  • 键无序:HashMap
  • 键排序:TreeMap
  • 键插入和取出顺序一致:LinkedHashMap
  • 对文件进行操作:Properties
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JAVA基础——集合 的相关文章

  • 如何在 JPA 中使用枚举

    我有一个电影租赁系统的现有数据库 每部电影都有一个评级属性 在 SQL 中 他们使用约束来限制该属性的允许值 CONSTRAINT film rating check CHECK rating text text OR rating tex
  • 如何获取枚举的子集

    大多数情况下 包含所有元素的枚举显示在用户界面的下拉列表中 我们只需要在用户界面中显示 5 个字段中的 2 个 通过某种方式利用可用于枚举的相同函数来获取此数据的更简单方法是什么 enum Color RED GREEN BLACK BLU
  • 按下按钮时清除编辑文本焦点并隐藏键盘

    我正在制作一个带有编辑文本和按钮的应用程序 当我在 edittext 中输入内容然后单击按钮时 我希望键盘和焦点在 edittext 上消失 但我似乎无法做到这一点 我在 XML 中插入了这两行代码 android focusable tr
  • Spring Data:限制自定义查询的结果

    在我的 Spring 数据存储库中 我 必须 使用自定义查询 Query注解 我知道我可以限制这样的命名查询中的结果数量 Iterable
  • 如何将列表转换为地图?

    最近我和一位同事讨论了转换的最佳方式是什么List to Map在 Java 中 这样做是否有任何具体的好处 我想知道最佳的转换方法 如果有人可以指导我 我将非常感激 这是个好方法吗 List
  • JPA:如何将字符串持久保存到数据库字段中,输入 MYSQL Text

    需求是用户可以写文章 所以我选择typeText为了contentmysql数据库内的字段 我怎样才能转换Java String into MySQL Text 干得好Jim Tough Entity public class Articl
  • 隐藏类的 System.out.print 调用

    我正在使用 java 库 jar 文件 该文件的作者放入了一堆System out print and System out printlns 有没有办法隐藏特定对象的这些消息 编辑 看起来jar文件似乎正在创建一堆线程 并且每个线程都有它
  • 根据哈希值确认文件内容

    我需要 检查完整性 content文件数量 文件将写入 CD DVD 可能会被复制多次 这个想法是识别正确复制的副本 在从 Nero 等中删除它们之后 我对此很陌生 但快速搜索表明Arrays hashCode byte http down
  • MongoDB:尝试从 JSON 读取 Long 导致 java.lang.Integer 无法转换为 java.lang.Long

    我有一个代码可以从 MongoDB 读取特定格式的数据 我需要测试一下 为此 我使用要测试的数据创建一个 JSON id ObjectId 57552e32e4b0839ede67e0af serial 574000690 startDat
  • 在java.util中获取错误ArrayList不带参数[重复]

    这个问题在这里已经有答案了 我已经创建了一个类 Student 现在我尝试将我的 Student 对象存储在 ArrayList 中 但在编译 ArrayList 不接受参数时出现错误 我已经检查了我的代码很多次 但找不到问题所在 我的学生
  • 在Java中使用BufferedWriter写入文件时监视文件大小?

    我正在将一个可能很长的项目列表写入文件 我正在写的项目的长度是可变的 如果生成的文件大小大于10M 则应将其分成多个文件 为了提高性能 我目前使用 BufferedWriter 如下所示 final FileOutputStream fos
  • Java中的OR运算(BitSet.class)

    如何编写一个程序 该程序需要001010101110000100100 011100010001000011000 000000000010000000000100 作为输入 位 输出将是OR其中 3 个 OR 0 0 0 0 1 1 1
  • java.lang.IllegalArgumentException:addChild:子名称“/”不唯一

    java lang IllegalArgumentException addChild 子名称 不唯一 通过在 tomcat webapps 文件夹中启用和禁用 saml 单点登录来替换现有 war 文件时遇到此问题 我正在使用 apach
  • 使用 include 进行 JAXB 剧集编译不起作用

    我有 2 个模式 A B 我在 B 中重用了一些 A 元素 我不使用命名空间 我在用着
  • wsdl 没有服务元素

    我必须使用 WCF Web 服务并获得 WSDL 外部的 因此无法控制 WSDL 在 WSDL 定义中 我没有找到包含服务 端口和地址元素的服务元素 WSDL 中不存在这种情况正常吗 这对于 WCF WSDL 来说很常见吗 我正在尝试使用轴
  • java Runtime.getRunTime().exec 和通配符?

    我正在尝试使用删除垃圾文件 Process p Runtime getRuntime exec 只要我不使用通配符 它 就可以正常工作 即 Process p Runtime getRuntime exec bin rm f specifi
  • 处理照片上传的最佳方式是什么?

    我正在为一个家庭成员的婚礼制作一个网站 他们要求的一个功能是一个照片部分 所有客人都可以在婚礼结束后前往并上传他们的照片 我说这是一个很棒的想法 然后我就去实现它 那么只有一个问题 物流 上传速度很慢 现代相机拍摄的照片很大 2 5 兆 我
  • 使用链接列表插入优先级队列的方法

    首先 我觉得我应该提到这是一项作业 我并不是在寻找直接的代码答案 只是为了指出正确的方向 我们被要求在链表中实现优先级队列 我正在努力编写 insert 函数的第一部分 在代码中我尝试检查是否head包含任何内容 如果没有则设置为head
  • 计算移动的球与移动的线/多边形碰撞的时间(2D)

    我有一个多边形 里面有一个移动的球 如果球撞到边界 它应该反弹回来 My current solution I split the polygon in lines and calculate when the ball hits the
  • 如何隐藏或删除 Android HoneyComb 中的状态栏?

    如何隐藏或删除 Android HoneyComb 中的状态栏 每次运行应用程序时 我都会发现某些内容必须被状态栏覆盖 我尝试改变AndroidManifest xml 但没有任何改变 你不知道 它被认为是永久的屏幕装饰 就像电容式主页 菜

随机推荐

  • Silverlight 1.1正式更名为Silverlight 2.0

    2007年11月30日 10 18 24 详情请参看下面两篇Blog http weblogs asp net scottgu archive 2007 11 29 net web product roadmap asp net silve
  • vscode快速生成标准的html代码

    Vsocde中 再新建html页面时 可以输入html 5然后按Tab或回车即可生成html模板 html 5
  • html5 webgl pyhon,WebGL基础

    WebGL坐标系 就像任何其他的3D系统 在WebGL中Z轴表示深x y和z轴 在WebGL的坐标被限制为 1 1 1 和 1 1 1 它意味着 如果你考虑该屏幕上投影的WebGL图形为立方体 则立方体的一个角将是 1 1 1 和相对的角为
  • PHPExcel导出

    PHPExcel导出 PHPExcel导出之前只做过简单的 这一次这个有些复杂的 包括单元格合并 字体的样式 边框线 单元格的背景色 单元格内容的自动换行 代码呈上 引入PHPExcel import Org Util PHPExcel i
  • 网络编程4——错误处理函数的封装和readn,readline封装思想说明

    系统调用不能保证每次都成功 必须进行出错处理 这样一方面可以保证程序逻辑正常 另一方面可以迅速得到故障信息 为使错误处理的代码不影响主程序的可读性 我们把与socket相关的一些系统函数加上错误处理代码包装成新的函数 叫做一个模块wrap
  • c++ 学习之 初始化列表初始化属性

    前言 我们来学习一下如何利用初始化列表来初始化属性 相较于我们所一般用的构造函数来初始化属性又有什么不同呢 正文 我们一般情况下是如何初始话属性的 先看代码 define CRT SECURE NO WARINGS using namesp
  • 多目标进化算法-约束问题的处理方法

    多目标进化算法系列 多目标进化算法 MOEA 概述 多目标优化 测试问题及其Pareto前沿 多目标进化算法详述 MOEA D与NSGA2优劣比较 多目标进化算法 约束问题的处理方法 基于C 的多目标进化算法平台MOEAPlat实现 MOE
  • Vue3 --父子组件生命周期

    渲染加载过程 mermaid svg cfIpXJJ2wAergAY1 label font family trebuchet ms verdana arial font family var mermaid font family fil
  • Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] ...

    警告的位置在matplotlib image中 从源码可知如果图像 np array 数值范围小于0或者大于1 或255 则会用np clip将其截断
  • Anaconda环境中pip命令找不到解决方案

    Anaconda环境中pip命令找不到解决方案 第一步 利用easy install安装pip easy install pip 参考链接 https www pythonheidong com blog article 406204 87
  • Spring AOP 自定义注解检查请求头(示例)

    代码传送门 需求 一个 Controller 可以处理 HTTP 请求 RestController public class DemoController GetMapping hello public String hello Requ
  • 配置nginx代理grafana实现域名访问

    目的 通过Nginx服务器对grafana进行代理 实现通过https 域名 grafana在公网进行访问 实践过程 1 修改Nginx配置 nginx conf 文件 添加访问grafana的配置 配置时注意proxy pass后面一定要
  • 微信JSSDK引入微信开发

    微信JS SDK是微信公众平台面向网页开发者提供的基于微信内的网页开发工具包 通过使用微信JS SDK 网页开发者可借助微信高效地使用拍照 选图 语音 位置等手机系统的能力 同时可以直接使用微信分享 扫一扫 卡券 支付等微信特有的能力 为微
  • 线性代数的本质——学习笔记

    线性代数的本质 学习笔记 该课程为b站上 3Blue1Brown大佬出的一系列线代视频 花了几天时间好好消化了一下 受益匪浅 欢迎各位没看懂视频的老哥过来看看我的理解 有什么错误也希望能指出 非常感谢 1 向量究竟是什么 向量的表示 建议
  • Google云数据库的“Enterprise“和“Enterprise Plus“版怎么选

    最近 Google Cloud SQL Google云上的RDS 做了一次大的产品调整与发布 将原来的Cloud SQL分为了两个版本 分别为 Enterprise 和 Enterprise Plus 版本 本文概述了两个版本的异同 以帮助
  • [UE4] UI部分

    UE4 UI部分 UMG基础 蓝图 几点思考 UMG和C 交互 UI基础控件和自定义控件 基础控件 自定义控件 3D UI UI适配 优化 UI开发示例 UI对话事件 SVN进行UE4项目协作 问题记录 UMG基础 虚幻示意图形界面设计器
  • HBuilderX低版本安装高版本组件库插件(HBuilderX 离线安装插件)

    背景 因为教学视频安装下来的HBuilderX版本低于现发行的 但是插件是最新版 想要使用到组件插件 特此记录方法步骤 windows 打开资源管理器 进入HBuilderX安装目录 进入plugins目录 将插件文件夹 放置到此目录 如是
  • Go_秒懂函数、参数、可变参数、匿名函数、内置函数

    函数是将具有独立功能的代码块组成一个整体 使其具有特殊功能的代码集 它将复杂的算法过程分解为若干个小任务 使程序结构更加清晰 易于维护 通过调用完成一段算法指令 输出或存储相关结果 因此 函数还是代码复用和测试的基本单元 关键字func用于
  • (基础)JavaScript迭代器[Symbol.iterator]

    迭代器就是为实现对不同集合进行统一遍历操作的一种机制 只要给需要遍历的数据结构部署Iterator接口 通过调用该接口 或者使用消耗该接口的API实现遍历操作 迭代器 iterator 是确使用户可在容器对象 container 例如链表或
  • JAVA基础——集合

    文章目录 前言 一 集合概要及框架体系 1 集合的理解 2 数组的缺点 3 集合的好处 4 集合的框架体系 二 Collection集合 单列集合 Collection集合特点 Collection集合遍历元素方式 1 迭代器的遍历方式 2