中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java中keySet()方法的作用是什么

發布時間:2021-05-18 17:59:23 來源:億速云 閱讀:683 作者:Leah 欄目:編程語言

Java中keySet()方法的作用是什么?相信很多沒有經驗的人對此束手無策,為此本文總結了問題出現的原因和解決方法,通過這篇文章希望你能解決這個問題。

  public Set<K> keySet() {
    Set<K> ks = keySet;
    if (ks == null) {
      ks = new KeySet();
      keySet = ks;
    }
    return ks;
  }

從代碼中了解到,第一次調用keySet方法時,keySet屬性是null,然后進行了初始化,再將keySet屬性返回。也就是說,HashMap里并不會隨著put和remove的進行也維護一個keySet集合,而是在第一次調用keySet方法時,才給keySet屬性初始化。

按照自己以往的理解,以為keySet返回的是一個集合,集合里面保存了HashMap的所有的Key。因為有了中先入為主的印象,所以讀源碼時,才感覺源碼很奇怪。從源碼中可以看到,初始化時,只是創建了一個KeySet類的對象,并沒有把HashMap的key都加入進來,方法就返回了。除了自己以往的理解外,還有一個現象,讓我堅信這時HashMap的key已經加入到keySet了,那就是在調試代碼過程中IDE給出的調試信息。如下圖。從圖中可以看出,創建完成KeySet()后,調試信息就已經可以顯示出,ks中有2個元素了。這個信息更加堅定了自己之前的理解。

Java中keySet()方法的作用是什么

那么,HashMap的key是什么時候加入到keySet集合中的呢?順著這個思路,我進行了一步一步的分析。自己看了KeySet類的構造函數,發現只有默認構造函數。那么我想,如果沒有在KeySet構造函數里把HashMap的key加入進來,那么就有可能是在KeySet的父類的構造函數中加入進來的。然后,自己找遍了KeySet類的父類的構造函數,發現都是空實現,并沒有任何加入HashMap的key的操作。這到底是怎么回事呢?

其實HashMap的key并沒有加入到keySet集合中,而是在遍歷的時候,使用迭代器對key進行的遍歷。這是結論。下面我們看一下原因和過程。

首先看一下KeySet類的代碼,如下圖。可以看到,KeySet類中的迭代器函數,返回的是一個KeyIterator類的對象。它的next方法返回的是HashIterator的nextNode的key。也就是說,當使用迭代器遍歷set內的元素時,KeySet類的迭代器,會保證能夠依次獲取到HashMap的節點的key值,這就是我們遍歷keySet的過程的實質。

  final class KeySet extends AbstractSet<K> {
    public final int size()         { return size; }
    public final void clear()        { HashMap.this.clear(); }
    public final Iterator<K> iterator()   { return new KeyIterator(); }
    public final boolean contains(Object o) { return containsKey(o); }
    public final boolean remove(Object key) {
      return removeNode(hash(key), key, null, false, true) != null;
    }
    public final Spliterator<K> spliterator() {
      return new KeySpliterator<>(HashMap.this, 0, -1, 0, 0);
    }
    public final void forEach(Consumer<? super K> action) {
      Node<K,V>[] tab;
      if (action == null)
        throw new NullPointerException();
      if (size > 0 && (tab = table) != null) {
        int mc = modCount;
        for (int i = 0; i < tab.length; ++i) {
          for (Node<K,V> e = tab[i]; e != null; e = e.next)
            action.accept(e.key);
        }
        if (modCount != mc)
          throw new ConcurrentModificationException();
      }
    }
  }
  final class KeyIterator extends HashIterator
    implements Iterator<K> {
    public final K next() { return nextNode().key; }
  }
  abstract class HashIterator {
    Node<K,V> next;    // next entry to return
    Node<K,V> current;   // current entry
    int expectedModCount; // for fast-fail
    int index;       // current slot
    HashIterator() {
      expectedModCount = modCount;
      Node<K,V>[] t = table;
      current = next = null;
      index = 0;
      if (t != null && size > 0) { // advance to first entry
        do {} while (index < t.length && (next = t[index++]) == null);
      }
    }
    public final boolean hasNext() {
      return next != null;
    }
    final Node<K,V> nextNode() {
      Node<K,V>[] t;
      Node<K,V> e = next;
      if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
      if (e == null)
        throw new NoSuchElementException();
      if ((next = (current = e).next) == null && (t = table) != null) {
        do {} while (index < t.length && (next = t[index++]) == null);
      }
      return e;
    }
    public final void remove() {
      Node<K,V> p = current;
      if (p == null)
        throw new IllegalStateException();
      if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
      current = null;
      K key = p.key;
      removeNode(hash(key), key, null, false, false);
      expectedModCount = modCount;
    }
  }

那么,這里我們可以思考這么一個問題。通過HashMap的keySet獲取到keySet后,難道只能用迭代器遍歷嗎?keySet方法不把HashMap的key都加入到set中,那么調用者使用for(int i = 0; i < size; i ++)的方式遍歷時,豈不是無法遍歷set中的key了嗎?是的,確實是的。keySet確實沒有把key加入到set中,另外,它不用擔心調用者用for(int i = 0; i < size; i ++)的方式遍歷時獲取不到key,因為set根本就沒有set.get(i)這樣類似的方法,要想遍歷set,只能用迭代器,或者使用foreach方式(本質還是迭代器)。

這里還有個問題需要解釋,就是在調試代碼時,既然key沒有加入到set中,那么IDE如何顯示出set中有2個元素這樣的信息的?原來,IDE顯示對象信息時,會調用對象的toString方法。而集合的toString方法就是顯示出集合中的元素個數。

這里再思考一步,如果我們在集合的toString方法加上斷點,那么IDE顯示對象信息時,會不先停下來?答案是看情況。記得早些年間使用eclipse調試代碼時,在toString方法加上斷點后,顯示對象信息時確實會停下來。然而我現在使用的是IDE是idea,idea在這一點上做了優化。如果是IDE顯示對象信息調用的toString方法,那么toString方法的斷點會被跳過,即不生效,但會給出一條提示信息,如下圖。如果程序員主動調用對象的toString方法,那么,toString方法的斷點會生效,可以正常斷點調試。

Java中keySet()方法的作用是什么

Java是什么

Java是一門面向對象編程語言,可以編寫桌面應用程序、Web應用程序、分布式系統和嵌入式系統應用程序。

看完上述內容,你們掌握Java中keySet()方法的作用是什么的方法了嗎?如果還想學到更多技能或想了解更多相關內容,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

云梦县| 渝北区| 靖远县| 湘潭市| 蒙阴县| 桐城市| 同德县| 昌邑市| 朔州市| 谷城县| 盈江县| 承德市| 开平市| 洛南县| 海原县| 延寿县| 嘉定区| 茶陵县| 邛崃市| 琼结县| 若尔盖县| 鄂托克前旗| 德钦县| 大化| 聂荣县| 仙游县| 陵水| 凤台县| 河间市| 旺苍县| 岢岚县| 北海市| 杭锦旗| 怀集县| 金川县| 鄂托克前旗| 城市| 马鞍山市| 苍山县| 登封市| 山阳县|