亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > Java > 正文

Java ArrayList.add 的實現方法

2024-07-14 08:42:46
字體:
來源:轉載
供稿:網友

ArrayList是平時相當常用的List實現, 其中boolean add(E e) 的實現比較直接:

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

有時候也使用 void add(int index, E element) 把元素插入到指定的index上. 在JDK中的實現是:

/** * 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++;}

略有差別, 需要保證當前elementData 數組容量夠用, 然后把從index處一直到尾部的數組元素都向后挪一位. 最后把要插入的元素賦給數組的index處.

一直以來, 我都認為 System.arraycopy 這個native方法, 它的c++實現是調用底層的memcpy, 直接方便, 效率也沒問題.

但今天看了openJDK的源碼發現并非如此.

以openJDK8u60 為例, 在objArrayKlass.cpp 中:

void ObjArrayKlass::copy_array(arrayOop s, int src_pos, arrayOop d,                int dst_pos, int length, TRAPS) { assert(s->is_objArray(), "must be obj array"); if (!d->is_objArray()) {  THROW(vmSymbols::java_lang_ArrayStoreException()); } // Check is all offsets and lengths are non negative if (src_pos < 0 || dst_pos < 0 || length < 0) {  THROW(vmSymbols::java_lang_ArrayIndexOutOfBoundsException()); } // Check if the ranges are valid if ( (((unsigned int) length + (unsigned int) src_pos) > (unsigned int) s->length())   || (((unsigned int) length + (unsigned int) dst_pos) > (unsigned int) d->length()) ) {  THROW(vmSymbols::java_lang_ArrayIndexOutOfBoundsException()); } // Special case. Boundary cases must be checked first // This allows the following call: copy_array(s, s.length(), d.length(), 0). // This is correct, since the position is supposed to be an 'in between point', i.e., s.length(), // points to the right of the last element. if (length==0) {  return; } if (UseCompressedOops) {  narrowOop* const src = objArrayOop(s)->obj_at_addr<narrowOop>(src_pos);  narrowOop* const dst = objArrayOop(d)->obj_at_addr<narrowOop>(dst_pos);  do_copy<narrowOop>(s, src, d, dst, length, CHECK); } else {  oop* const src = objArrayOop(s)->obj_at_addr<oop>(src_pos);  oop* const dst = objArrayOop(d)->obj_at_addr<oop>(dst_pos);  do_copy<oop> (s, src, d, dst, length, CHECK); }}

可以看到copy_array在做了各種檢查之后, 最終copy的部分在do_copy方法中, 而這個方法實現如下:

// Either oop or narrowOop depending on UseCompressedOops.template <class T> void ObjArrayKlass::do_copy(arrayOop s, T* src,                arrayOop d, T* dst, int length, TRAPS) { BarrierSet* bs = Universe::heap()->barrier_set(); // For performance reasons, we assume we are that the write barrier we // are using has optimized modes for arrays of references. At least one // of the asserts below will fail if this is not the case. assert(bs->has_write_ref_array_opt(), "Barrier set must have ref array opt"); assert(bs->has_write_ref_array_pre_opt(), "For pre-barrier as well."); if (s == d) {  // since source and destination are equal we do not need conversion checks.  assert(length > 0, "sanity check");  bs->write_ref_array_pre(dst, length);  Copy::conjoint_oops_atomic(src, dst, length); } else {  // We have to make sure all elements conform to the destination array  Klass* bound = ObjArrayKlass::cast(d->klass())->element_klass();  Klass* stype = ObjArrayKlass::cast(s->klass())->element_klass();  if (stype == bound || stype->is_subtype_of(bound)) {   // elements are guaranteed to be subtypes, so no check necessary   bs->write_ref_array_pre(dst, length);   Copy::conjoint_oops_atomic(src, dst, length);  } else {   // slow case: need individual subtype checks   // note: don't use obj_at_put below because it includes a redundant store check   T* from = src;   T* end = from + length;   for (T* p = dst; from < end; from++, p++) {    // XXX this is going to be slow.    T element = *from;    // even slower now    bool element_is_null = oopDesc::is_null(element);    oop new_val = element_is_null ? oop(NULL)                   : oopDesc::decode_heap_oop_not_null(element);    if (element_is_null ||      (new_val->klass())->is_subtype_of(bound)) {     bs->write_ref_field_pre(p, new_val);     *p = element;    } else {     // We must do a barrier to cover the partial copy.     const size_t pd = pointer_delta(p, dst, (size_t)heapOopSize);     // pointer delta is scaled to number of elements (length field in     // objArrayOop) which we assume is 32 bit.     assert(pd == (size_t)(int)pd, "length field overflow");     bs->write_ref_array((HeapWord*)dst, pd);     THROW(vmSymbols::java_lang_ArrayStoreException());     return;    }   }  } } bs->write_ref_array((HeapWord*)dst, length);}

可以看到, 在設定了heap barrier之后, 元素是在for循環中被一個個挪動的. 做的工作比我想象的要多.

如果有m個元素, 按照給定位置, 使用ArrayList.add(int,E)逐個插入到一個長度為n的ArrayList中, 復雜度應當是O(m*n), 或者O(m*(m+n)), 所以, 如果m和n都不小的話, 效率確實是不高的.

效率高一些的方法是, 建立m+n長度的數組或ArrayList, 在給定位置賦值該m個要插入的元素, 其他位置依次賦值原n長度List的元素. 這樣時間復雜度應當是O(m+n).

還有, 在前面的實現中, 我們可以看到有對ensureCapacityInternal(int) 的調用. 這個保證數組容量的實現主要在:

/** * 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容量增長不是正好按照要求的容量minCapacity來設計的, 新容量計算的主要邏輯是: 如果要求容量比當前容量的1.5倍大, 就按照要求容量重新分配空間; 否則按當前容量1.5倍增加. 當然不能超出Integer.MAX_VALUE了. oldCapacity + (oldCapacity >> 1) 實際就是當前容量1.5倍, 等同于(int) (oldCapacity * 1.5), 但因這段不涉及浮點運算只是移位, 顯然效率高不少.

所以如果ArrayList一個一個add元素的話, 容量是在不夠的時候1.5倍增長的. 關于1.5這個數字, 或許是覺得2倍增長太快了吧. 也或許有實驗數據的驗證支撐.

關于這段代碼中出現的Arrays.copyOf這個方法, 實現的是重新分配一段數組, 把elementData賦值給新分配的空間, 如果新分配的空間大, 則后面賦值null, 如果分配空間比當前數組小則截斷. 底層還是調用的System.arraycopy.

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VeVb武林網。


注:相關教程知識閱讀請移步到JAVA教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产亚洲aⅴaaaaaa毛片| 久久久999成人| 国产成人在线精品| 色爱av美腿丝袜综合粉嫩av| 亚洲男女自偷自拍图片另类| 亚洲视频视频在线| 久久成年人视频| 亚洲欧美成人在线| 亚洲精品白浆高清久久久久久| 国产视频精品久久久| 国产精品大陆在线观看| 日韩不卡在线观看| 亚洲男人天堂手机在线| 成人av在线网址| 国产一区二区三区久久精品| 亚洲美女精品成人在线视频| 久久影院模特热| 亚洲一区二区三区乱码aⅴ| 国产精品久久久久久久久免费看| 亚洲欧美国内爽妇网| 国产精品三级久久久久久电影| 亚洲精品av在线| 理论片在线不卡免费观看| 日本久久久久久久| 日本亚洲欧洲色α| 97色伦亚洲国产| 欧美黑人巨大精品一区二区| 成人h视频在线观看播放| 91精品国产精品| 欧美日本高清视频| 不卡av电影在线观看| 国产精品美女www| 亚洲人成在线观看网站高清| 国产精品嫩草影院久久久| 亚洲欧美国产另类| 亚洲精品一区二三区不卡| 国产aⅴ夜夜欢一区二区三区| 亚洲缚视频在线观看| 日韩av理论片| 欧美高清激情视频| 伊人一区二区三区久久精品| 亚洲黄色av网站| 538国产精品一区二区免费视频| 国产91露脸中文字幕在线| 欧美激情在线有限公司| 一本色道久久综合狠狠躁篇的优点| 一本色道久久综合亚洲精品小说| 日韩电影在线观看永久视频免费网站| 欧美一区三区三区高中清蜜桃| 亚洲欧美日韩精品久久| 亚洲激情在线观看| 性色av一区二区三区| 国产日韩欧美中文在线播放| 最新国产成人av网站网址麻豆| 亚洲第一页中文字幕| 欧美在线免费视频| 国产精品ⅴa在线观看h| 欧美精品videossex88| 国产精品夫妻激情| 97色在线观看| 91久久精品美女高潮| 欧美日韩成人精品| 97色伦亚洲国产| 欧美成人激情视频免费观看| 91国产一区在线| 久久久亚洲精品视频| 国产午夜精品一区理论片飘花| 92国产精品视频| 欧美国产亚洲精品久久久8v| 国产99视频精品免视看7| 97av在线播放| 欧美视频在线看| 国产91精品最新在线播放| 亚洲性无码av在线| 国产亚洲精品一区二区| 国产日本欧美在线观看| 日韩精品极品毛片系列视频| 亚洲香蕉在线观看| 青青青国产精品一区二区| 日韩大陆欧美高清视频区| 色综合色综合久久综合频道88| 亚洲成人xxx| 国产精品久久久| 欧美精品18videos性欧美| 精品亚洲一区二区三区在线播放| 色综合天天综合网国产成人网| 国产精品视频久久久| 国产成人精品最新| 国产亚洲一区精品| 国产精品一区二区三区在线播放| 97欧美精品一区二区三区| 欧美做受高潮1| 91精品国产电影| 性色av一区二区三区在线观看| 精品久久国产精品| 国产精品夜色7777狼人| 自拍偷拍亚洲一区| 在线日韩精品视频| 日韩黄在线观看| 中文字幕久久久av一区| 国产日韩在线一区| 中国日韩欧美久久久久久久久| 亚洲精品美女网站| 亚洲国产精久久久久久| 国产精品普通话| 精品久久久国产| 欧美一区二区大胆人体摄影专业网站| 欧美在线亚洲一区| 国内精品久久久久伊人av| 国产日韩综合一区二区性色av| 国产成人精品优优av| 一区二区三区黄色| 国产精品444| 欧美激情精品久久久久久久变态| 91大神在线播放精品| 国产中文欧美精品| 欧美最猛性xxxxx(亚洲精品)| 亚洲人成亚洲人成在线观看| 亚洲第一福利在线观看| 日韩av在线一区二区| 久久久久久免费精品| 麻豆乱码国产一区二区三区| 亚洲女人被黑人巨大进入al| 亚洲美女免费精品视频在线观看| 欧美劲爆第一页| 亚洲男人av在线| 亚洲精品成a人在线观看| 久热国产精品视频| 国产成人精品在线| 欧美性受xxxx白人性爽| 乱亲女秽乱长久久久| 亚洲天堂男人天堂女人天堂| 日韩有码片在线观看| 美女福利视频一区| 国产精品亚洲综合天堂夜夜| 91高清免费在线观看| 欧美性猛交xxxx免费看漫画| 在线色欧美三级视频| 国内精品久久久久久久久| 精品成人在线视频| 国产91对白在线播放| 国产精品成人观看视频国产奇米| 在线亚洲男人天堂| 欧美在线视频免费观看| 日韩成人中文字幕在线观看| 91成人免费观看网站| 亚洲自拍偷拍色图| 亚洲区免费影片| 欧美孕妇性xx| 欧美视频裸体精品| 国产不卡视频在线| 久久精品国产亚洲7777| 国产精品久久久久久中文字| 91精品国产91久久久久久吃药| 久久综合久久八八| 97视频com| 国产成人中文字幕| 国产亚洲一区二区在线| 51色欧美片视频在线观看| 一道本无吗dⅴd在线播放一区| 国产精品久久久久久中文字| 欧美噜噜久久久xxx| 国产精品嫩草影院久久久| www.久久久久久.com|