JavaRush /จาวาบล็อก /Random-TH /การวิเคราะห์โดยละเอียดของคลาส ArrayList [ตอนที่ 1]
Vonorim
ระดับ

การวิเคราะห์โดยละเอียดของคลาส ArrayList [ตอนที่ 1]

เผยแพร่ในกลุ่ม
บทความนี้จะดูรายละเอียดเกี่ยวกับคลาส ArrayList จาก Collections Framework ซึ่งอาจเป็นวิธีที่ง่ายที่สุดที่จะเข้าใจ เนื่องจากคลาสนี้ใช้อาร์เรย์ปกติ คุณเกือบจะถูกถามคำถามเกี่ยวกับคลาสนี้และการนำไปใช้งานใน Java ในการสัมภาษณ์อย่างแน่นอน ในส่วนที่สอง เราจะวิเคราะห์วิธีการที่เหลือและเขียนการใช้งานอาร์เรย์แบบไดนามิกสำหรับตัวเลขของเราเอง คลาส ArrayList สืบทอดมาจากคลาส AbstractList และใช้อินเทอร์เฟซต่อไปนี้: List, RandomAccess, Cloneable, Serializable การวิเคราะห์โดยละเอียดของคลาส ArrayList [ตอนที่ 2] การวิเคราะห์โดยละเอียดของคลาส ArrayList [ตอนที่ 1] - 1คลาส ArrayList รองรับอาร์เรย์แบบไดนามิกที่สามารถขยายได้ตามต้องการ ความจำเป็นและประสิทธิผลของอาร์เรย์อธิบายได้จากข้อเท็จจริงที่ว่าอาร์เรย์ปกติมีความยาวคงที่ เมื่อสร้างขึ้นแล้ว จะไม่สามารถขยายหรือลดขนาดได้ ซึ่งจะกำหนดข้อจำกัดหากไม่ทราบว่าจำเป็นต้องใช้อาร์เรย์ขนาดใหญ่เพียงใด โดยพื้นฐานแล้วคลาส ArrayList คืออาร์เรย์รายการที่มีความยาวผันแปรได้ของการอ้างอิงอ็อบเจ็กต์ สิ่งสำคัญคือต้องเข้าใจว่าขนาด (จำนวนเซลล์) ของอาร์เรย์ภายในจะไม่ลดลงโดยอัตโนมัติเมื่อองค์ประกอบถูกลบออกจากอาร์เรย์ ในความเป็นจริง ค่าของตัวแปรsizeซึ่งระบุจำนวนองค์ประกอบที่มีอยู่ในอาร์เรย์นั้นลดลง สมมติว่าเราสร้างอ็อบเจ็กต์ใหม่ของคลาส ArrayList และเพิ่มองค์ประกอบ 5 รายการลงไป ตามค่าเริ่มต้น อาร์เรย์ที่มี 10 องค์ประกอบจะถูกสร้างขึ้น ในกรณีนี้ สิ่งที่เรียกว่าความจุ (ขนาด/ปริมาตร) ของออบเจ็กต์ของเราจะเท่ากับ 10 แต่ค่าของตัวแปรsizeจะเท่ากับ 5 และเมื่อเราลบองค์ประกอบ เราจะเห็นการเปลี่ยนแปลงในค่าของตัวแปรsizeเนื่องจากเรา.lengthไม่สามารถเข้าถึงอาร์เรย์ภายในของคลาส ArrayList และค้นหาความยาวของมันได้ สามารถลดขนาดได้โดยใช้วิธีการเพิ่มเติมtrimToSize()ซึ่งจะกล่าวถึงด้านล่าง มาดูที่สนามของชั้นเรียนกัน
  • ฟิลด์ที่รับผิดชอบปริมาณเริ่มต้นของอาร์เรย์ไดนามิก:

    private static final int DEFAULT_CAPACITY = 10

    เมื่อสร้างวัตถุใหม่ new ArrayList<>() (ตัวสร้างที่ไม่มีพารามิเตอร์) จะมีการสร้างอาร์เรย์ 10 องค์ประกอบภายใน

  • ฟิลด์ที่องค์ประกอบทั้งหมดของคอลเลกชันจะถูกจัดเก็บ:

    transient Object[] elementData

    ทำเครื่องหมายด้วยคำสำคัญtransient- ฟิลด์จะไม่ถูกเขียนลงในสตรีมไบต์เมื่อใช้อัลกอริธึมการทำให้เป็นอนุกรมมาตรฐาน เป็นที่น่าสังเกตว่าฟิลด์นี้ไม่ได้ทำเครื่องหมายด้วยคำหลักprivateแต่สิ่งนี้เสร็จสิ้นเพื่ออำนวยความสะดวกในการเข้าถึงฟิลด์นี้จากคลาสที่ซ้อนกัน (เช่น SubList)

  • ฟิลด์ตัวนับที่เก็บจำนวนองค์ประกอบจริงในอาร์เรย์:

    private int size

    ค่าจะเพิ่มขึ้น/ลดลงเมื่อดำเนินการต่างๆ เช่น การแทรกและการลบ

ในชั้นเรียนยังมีช่องข้อมูลอีก 3 ช่อง แต่โดยพื้นฐานแล้วเป็นช่องเพิ่มเติม จึงไม่มีประโยชน์ที่จะพิจารณาช่องเหล่านั้น คลาสนี้มีคอนสตรัคเตอร์สามตัว:
  1. public ArrayList()– สร้างอาร์เรย์รายการว่าง 10 องค์ประกอบ
  2. public ArrayList(Collection < ? extends E > c)– สร้างอาร์เรย์รายการเริ่มต้นด้วยองค์ประกอบจากคอลเลกชันที่ส่งผ่าน (หากเราต้องการสร้าง ArrayList ใหม่ตามคอลเลกชันบางส่วน)
  3. public ArrayList(int initialCapacity)– สร้างอาร์เรย์รายการที่มีความจุเริ่มต้น หากพารามิเตอร์ที่ส่งผ่าน defaultCapacity มากกว่า 0 แสดงว่าอาร์เรย์ของขนาดที่ระบุจะถูกสร้างขึ้น (ฟิลด์ภายใน elementData ได้รับการกำหนดลิงก์ไปยังอาร์เรย์ประเภท Object ใหม่ที่มีขนาด defaultCapacity) หากพารามิเตอร์เป็น 0 แสดงว่าอาร์เรย์ว่างจะถูกสร้างขึ้น หากพารามิเตอร์ที่ระบุน้อยกว่า 0 แสดงว่า IllegalArgumentException ถูกส่งออกไป
การสร้างวัตถุ
List < String> list = new ArrayList<>();
วัตถุที่สร้างขึ้นใหม่มีlistคุณสมบัติ (เขตข้อมูล) elementDataและ sizeที่เก็บค่านั้นelementDataไม่มีอะไรมากไปกว่าอาร์เรย์ประเภทเฉพาะ (ระบุในรูปแบบทั่วไป – <>) ในกรณีของString[]เรา หากเรียกใช้คอนสตรัคเตอร์ที่ไม่มีพารามิเตอร์ ตามค่าเริ่มต้นอาร์เรย์ขององค์ประกอบ 10 ประเภท Object จะถูกสร้างขึ้น (แน่นอนว่าต้องมีการส่งประเภท) การวิเคราะห์โดยละเอียดของคลาส ArrayList [ตอนที่ 1] - 2การเพิ่มองค์ประกอบ การเพิ่มองค์ประกอบแบบคลาสสิกให้กับอาร์เรย์รายการทำได้โดยใช้ตัวแปรที่โอเวอร์โหลดของadd().
public boolean add(E элемент)
เรามาเพิ่มกันดีกว่า: list.add("0"); การวิเคราะห์โดยละเอียดของคลาส ArrayList [ตอนที่ 1] - 3ภายในวิธีนี้ มีการเรียกเวอร์ชันที่โอเวอร์โหลดของเมธอดadd()โดยทำเครื่องหมายเป็นprivateซึ่งจะรับพารามิเตอร์สามตัวเป็นอินพุต: องค์ประกอบที่จะเพิ่ม อาร์เรย์ภายใน และขนาดของมัน ในวิธีการส่วนตัว การตรวจสอบจะเกิดขึ้น: หากพารามิเตอร์ขนาดที่ส่งผ่านเท่ากับความยาวของอาร์เรย์ภายใน (นั่นคืออาร์เรย์เต็ม) จากนั้นอาร์เรย์จะถูกกำหนดผลลัพธ์ของวิธีการgrow(int minCapacity)(ค่าปัจจุบันของฟิลด์ ขนาด + 1 ถูกส่งไปยังวิธีการเนื่องจากจำเป็นต้องคำนึงถึงองค์ประกอบที่ถูกเพิ่ม) ซึ่งอาร์เรย์ภายในถูกกำหนดลิงก์ไปยังอาร์เรย์ที่สร้างขึ้นใหม่ที่ได้รับโดยการคัดลอกองค์ประกอบของอาร์เรย์ดั้งเดิม:
Arrays.copyOf(elementData, newCapacity(minCapacity))
เนื่องจากเป็นพารามิเตอร์ตัวที่สองของเมธอดcopyOfเราจะระบุผลลัพธ์ของเมธอดnewCapacity(int minCapacity)ซึ่งมีการคำนวณขนาดอาร์เรย์ใหม่ภายใน คำนวณโดยใช้สูตรต่อไปนี้: int newCapacity = oldCapacity + (oldCapacity >> 1) สำหรับอาร์เรย์ที่มีขนาดเริ่มต้น ค่าต่อไปนี้จะเป็นจริง: >> 1– เลื่อนบิตไปทางขวาทีละหนึ่ง (ตัวดำเนินการที่ลดจำนวนลงครึ่งหนึ่ง) โดยพื้นฐานแล้วมันหมายถึงการหารด้วย 2 ยกกำลัง 1 ปรากฎว่าเราหาร 10 ด้วย 2 แล้วบวก 10 รวมแล้ว ความจุใหม่ของอาเรย์คือ 15 แต่เนื่องจากเราเพิ่มองค์ประกอบที่ 11 จึงเป็น 15 + 1 = 16. กลับไปที่รายการของเราและสมมติว่าเราได้เพิ่มองค์ประกอบไปแล้ว 10 รายการแล้วลองเพิ่ม 11 รายการ การตรวจสอบจะแสดงว่าไม่มีช่องว่างในอาร์เรย์ ดังนั้นอาร์เรย์ใหม่จะถูกสร้างขึ้นและเรียกว่าArrays.copyOfซึ่งใช้เมธอดของระบบเป็นการSystem.arraycopy()ภายใน การวิเคราะห์โดยละเอียดของคลาส ArrayList [ตอนที่ 1] - 4การวิเคราะห์โดยละเอียดของคลาส ArrayList [ตอนที่ 1] - 5หรือนี่คือตัวอย่างที่ชัดเจนจากบทความหนึ่งเกี่ยวกับ JavaRush: การวิเคราะห์โดยละเอียดของคลาส ArrayList [ตอนที่ 1] - 6หลังจากตรวจสอบทั้งหมดนี้และเพิ่มขนาดของอาร์เรย์หากจำเป็น จากนั้นในวิธีส่วนตัวadd()องค์ประกอบใหม่จะถูกเพิ่มที่ส่วนท้ายของอาร์เรย์ และพารามิเตอร์ปัจจุบันsizeจะเพิ่มขึ้นหนึ่งรายการ . อาร์เรย์เก่าจะถูกประมวลผลโดยตัวรวบรวมขยะในภายหลัง นี่คือวิธีการทำงานของอาร์เรย์แบบไดนามิก: เมื่อเราเพิ่มองค์ประกอบ เราจะตรวจสอบว่ายังมีที่ว่างในนั้นหรือไม่ หากมีช่องว่าง เราก็เพียงเพิ่มองค์ประกอบที่ส่วนท้ายของอาร์เรย์ จุดสิ้นสุดไม่ได้หมายถึงเซลล์สุดท้ายในอาร์เรย์ แต่เป็นเซลล์ที่สอดคล้องกับsizeค่า เราได้เพิ่มองค์ประกอบแรกลงในอาร์เรย์ โดยวางไว้ในเซลล์ที่มีดัชนี [0] ค่าฟิลด์sizeเพิ่มขึ้นหนึ่งและ = 1 เราเพิ่มองค์ประกอบถัดไป: เราเห็นว่าsize = 1ดังนั้นเราจึงวางองค์ประกอบในเซลล์ที่มีดัชนี [1] และอื่น ๆ มีเมธอดเวอร์ชันโอเวอร์โหลดที่มีพารามิเตอร์สองตัว:
public void add(int index, E element)
เราสามารถระบุตำแหน่ง (ดัชนี) ของเซลล์ที่เราต้องการเพิ่มองค์ประกอบได้ ขั้นแรก ตรวจสอบความถูกต้องของค่าดัชนีที่ระบุ เนื่องจากมีความเป็นไปได้ที่ดัชนีที่ไม่ถูกต้องจะถูกระบุ ซึ่งจะชี้ไปที่เซลล์ที่ไม่มีอะไรเลย หรือไม่มีอยู่เลย การตรวจสอบดัชนี: index > size || index < 0– หากดัชนีที่ระบุมีขนาดใหญ่กว่าขนาดปัจจุบันของอาร์เรย์หรือน้อยกว่า 0 ข้อยกเว้นจะถูกส่งออกIndexOutOfBoundsExceptionไป จากนั้น หากจำเป็น ขนาดของอาร์เรย์จะเพิ่มขึ้น คล้ายกับตัวอย่างด้านบน คุณคงเคยได้ยินมาว่าในระหว่างการเพิ่ม/ลบการดำเนินการในอาร์เรย์ มีบางอย่างถูกเลื่อนไปที่ไหนสักแห่ง (ไปทางขวาหรือทางซ้าย) ดังนั้น การเปลี่ยนแปลงจะดำเนินการโดยการคัดลอกอาร์เรย์: System.arraycopy(elementData, index, elementData, index + 1, s - index); องค์ประกอบทั้งหมดที่อยู่ทางด้านขวาของดัชนีที่ระบุจะถูกเลื่อนไปทางขวาหนึ่งตำแหน่ง (ดัชนี +1) และหลังจากนั้นองค์ประกอบใหม่จะถูกเพิ่มลงในอาร์เรย์ภายในตามดัชนีที่ระบุ เนื่องจากเราได้เลื่อนส่วนหนึ่งของอาร์เรย์ไปทางขวาทีละหนึ่ง (ไม่ได้สร้างอาร์เรย์ใหม่) เซลล์ที่เราต้องการจึงมีอิสระในการเขียน ลิงก์ไปยังอาเรย์เก่าจะถูกลบและในอนาคตจะถูกยึดครองโดยตัวรวบรวมขยะ วาง "maserati" ลงในเซลล์ [3] ซึ่งถูกครอบครองแล้ว:
การวิเคราะห์โดยละเอียดของคลาส ArrayList [ตอนที่ 1] - 7
ดังนั้นเมื่อองค์ประกอบถูกแทรกที่ดัชนีและไม่มีพื้นที่ว่างในอาร์เรย์ การเรียกSystem.arraycopy()จะเกิดขึ้นสองครั้ง: ครั้งแรกใน ครั้งgrow()ที่สองในวิธีการนั้นเองadd(index, value)ซึ่งจะส่งผลต่อความเร็วของการดำเนินการเพิ่มทั้งหมดอย่างชัดเจน เป็นผลให้เมื่อจำเป็นต้องเขียนองค์ประกอบอื่นลงในอาร์เรย์ภายใน แต่ไม่มีที่ว่างดังนั้นนี่คือสิ่งที่เกิดขึ้นภายใน ArrayList:
  • อาร์เรย์ใหม่จะถูกสร้างขึ้นโดยมีขนาดใหญ่กว่าอาร์เรย์เดิมถึง 1.5 เท่า บวกด้วยองค์ประกอบหนึ่งรายการ
  • องค์ประกอบทั้งหมดจากอาร์เรย์เก่าจะถูกคัดลอกไปยังอาร์เรย์ใหม่
  • อาร์เรย์ใหม่จะถูกเก็บไว้ในตัวแปรภายในของวัตถุ ArrayList และอาร์เรย์เก่าจะถูกประกาศเป็นขยะ
ความจุของวัตถุประเภท ArrayList สามารถเพิ่มได้ด้วยตนเองโดยใช้วิธีการ:
public void ensureCapacity(int minCapacity)
ด้วยการเพิ่มความจุอาเรย์ล่วงหน้า คุณสามารถหลีกเลี่ยงการแจกจ่าย RAM เพิ่มเติมในภายหลังได้ วิธีการนี้จะเพิ่มขนาดของอาร์เรย์ภายในเพื่อรองรับจำนวนองค์ประกอบที่ส่งผ่านไปminCapacityยัง วิธีการนี้ensureCapacity()ไม่ส่งผลกระทบต่อฟิลด์sizeแต่จะส่งผลต่อcapacity(ขนาดของ) อาร์เรย์ภายใน ฉันขอย้ำอีกครั้งว่าsizeทั้งสองcapacityสิ่งต่างกันและมันสำคัญมากที่จะไม่สับสน! หากคุณต้องการลดขนาดของอาร์เรย์พื้นฐานที่ใช้สร้าง ArrayList ให้เป็นจำนวนองค์ประกอบปัจจุบันที่เก็บไว้จริง คุณควรเรียกtrimToSize(). หลังจากลบองค์ประกอบออกจากคอลเลกชันแล้วsize()มันจะแสดงจำนวนองค์ประกอบที่มีอยู่จริง และcapacityจะไม่ลดลง! สมมติว่า: เราป้อน 100 องค์ประกอบลบ 50 รายการแรกsizeมันจะเท่ากับ 50 และจะcapacityยังคงอยู่ 100 เพื่อลด และcapacityเราจำเป็นต้องใช้วิธีการtrimToSize()ซึ่งปรับความจุทั้งหมดของเราให้เป็นขนาดปัจจุบัน มันพอดียังไงบ้าง? คัดลอกอาร์เรย์ของเราเพื่อไม่ให้มีเซลล์ว่างเหลืออยู่ (ความยาวของอาร์เรย์ใหม่จะเท่ากับฟิลด์ขนาด)
การวิเคราะห์โดยละเอียดของคลาส ArrayList [ตอนที่ 1] - 8
คุณยังสามารถเพิ่มองค์ประกอบต่างๆ ให้กับคอลเลกชันของเราได้โดยใช้นามสกุลไฟล์addAll.
public boolean addAll(Collection< ? extends E> c)
public boolean addAll(int index, Collection< ? extends E> collection);
ตัวเลือกแรกช่วยให้คุณสามารถเพิ่มองค์ประกอบทั้งหมดจากคอลเลกชันที่ระบุในพารามิเตอร์วิธีการ (เช่น แผ่นงานอื่น) ไปยังคอลเลกชันดั้งเดิม (แทรกที่ส่วนท้าย) ที่มีการเรียกใช้เมธอด คอลเลกชันที่ส่งผ่าน (อาจเป็นชุดก็ได้) จะถูกแปลงเป็นอาร์เรย์โดยใช้นามสกุลtoArray(). โดยปกติแล้ว การดำเนินการเพิ่มจะดำเนินการโดยใช้การคัดลอกด้วย ประการที่สองคือการเพิ่มองค์ประกอบทั้งหมดcollectionลงในรายการโดยเริ่มจากindexดัชนี ในกรณีนี้ องค์ประกอบทั้งหมดจะเลื่อนไปทางขวาตามจำนวนองค์ประกอบในcollectionรายการ การลบองค์ประกอบ ขั้นแรก มาดูตัวเลือกคลาสสิกสำหรับการลบองค์ประกอบออกจาก ArrayList
public E remove(int index)
ดำเนินการลบตามดัชนีและเลื่อนองค์ประกอบที่ตามมาทั้งหมด (หลังจากองค์ประกอบที่ดัชนีที่ระบุ) ไปทางซ้าย ดังนั้นจึงเป็นการปิด "รู" นอกจากนี้ยังส่งคืนองค์ประกอบที่ถูกลบ (E) ซึ่งก่อนหน้านี้ถูกเขียนไปยังตัวแปรเพิ่มเติมก่อนการลบ ซึ่งเป็นค่าที่เราได้รับจากการเรียกเมธอด เพื่อทำความเข้าใจว่า E คืออะไร คุณจะต้องทำความคุ้นเคยกับสิ่งที่เรียกว่าประเภททั่วไป สัญกรณ์ E บ่งชี้ว่าวิธีการส่งคืนประเภทข้อมูลที่ระบุไว้เมื่อสร้างวัตถุ ArrayList (โปรดจำไว้ว่า: List <String> listดังนั้นในกรณีนี้ E จะถูก “ทดแทน” String) เพื่อความเข้าใจโดยทั่วไป ฉันขอแนะนำอย่างยิ่งให้คุณทำความคุ้นเคยกับประเภททั่วไป มีการตรวจสอบความถูกต้องของดัชนีที่ป้อน จากนั้นภายในเมธอดองค์ประกอบจะไม่ถูกลบทั้งหมด แต่จะเรียกว่าเมธอดส่วนตัวfastRemove(Object[] es, int i)ซึ่งการลบเกิดขึ้นแล้ว เราส่งผ่านอาร์เรย์ของเราและดัชนีที่ระบุไปยังวิธีการเป็นอินพุต องค์ประกอบจะถูกคัดลอกโดยใช้System.arraycopy()ขนาดของอาร์เรย์จะลดลง จากนั้นเราจะกำหนดค่าว่างให้กับองค์ประกอบสุดท้าย เป็นที่น่าสังเกตว่าไม่มีการสร้างอาร์เรย์ใหม่: System.arraycopy(es, i + 1, es, i, size - 1 - i); ส่วนที่อยู่ทางด้านขวาของตำแหน่งภายใต้ดัชนีที่ระบุ (i+1) จะถูกคัดลอกไปยังอาร์เรย์ดั้งเดิมของเรา (es) และเริ่มต้นจากตำแหน่งนั้น (i) ตำแหน่งที่องค์ประกอบนั้นถูกลบออก ดังนั้นเราจึงทำการเลื่อนไปทางซ้ายและลบองค์ประกอบของเรา
Подробный разбор класса ArrayList [Часть 1] - 9
ลองลบองค์ประกอบที่ดัชนี 3 ออกจากอาร์เรย์ด้านล่าง:
Подробный разбор класса ArrayList [Часть 1] - 10
ลองพิจารณาวิธีการรุ่นที่สอง:
public boolean remove(Object o)
วิธีการลบองค์ประกอบที่ส่งผ่านออกจากรายการoหรือแม่นยำยิ่งขึ้นคือวัตถุที่ลิงก์ที่ระบุ หากมีองค์ประกอบอยู่ในรายการ องค์ประกอบนั้นจะถูกลบออกและองค์ประกอบทั้งหมดจะเลื่อนไปทางซ้าย หากมีองค์ประกอบอยู่ในรายการและถูกลบออกสำเร็จ เมธอดจะคืนค่าเป็นจริง มิฉะนั้นจะเป็นเท็จ คล้ายกับตัวเลือกที่มีการลบตามดัชนี วิธีการนี้เรียกว่าfastRemove()โดยที่การกระทำเดียวกันจะเกิดขึ้นทุกประการ ข้อแตกต่างก็คือวิธีการremove(Object o)ค้นหาวัตถุที่ต้องการเพิ่มเติมผ่านวิธีการequals()ของคลาส Object เมื่อลบตามค่า การวนซ้ำจะผ่านองค์ประกอบทั้งหมดของรายการจนกว่าจะพบรายการที่ตรงกัน เฉพาะองค์ประกอบแรกที่พบเท่านั้นที่จะถูกลบ สรุป: เมื่อลบองค์ประกอบออกจากอาร์เรย์แบบไดนามิก จะไม่เหลือรูเหมือนในอาร์เรย์ปกติ (เซลล์ที่ถูกลบจะไม่ว่างเปล่า) องค์ประกอบที่ตามมาทั้งหมด (ซึ่งอยู่ทางด้านขวาของดัชนี) จะถูกเลื่อนไปทางซ้ายหนึ่งตำแหน่ง มีวิธีการเพิ่มเติมหลายวิธีที่สามารถใช้เพื่อลบองค์ประกอบออกจากรายการตามระดับที่แตกต่างกัน ลองดูพวกเขาสั้น ๆ ทำความสะอาดคอลเลกชันของเรา:
public void clear()
การวนซ้ำอย่างง่ายforจะวนซ้ำองค์ประกอบทั้งหมดของอาร์เรย์ โดยกำหนดค่าว่างให้กับแต่ละองค์ประกอบ คุณสามารถลบองค์ประกอบเหล่านั้นออกจากคอลเลกชันของเราที่มีอยู่ในคอลเลกชันที่ถ่ายโอนอื่นได้ดังนี้:
public boolean removeAll(Collection< ?> c)
หากคุณต้องการลบองค์ประกอบหลายรายการ คุณไม่ควรทำในลักษณะวนซ้ำแบบมีเงื่อนไข: สะดวกกว่าและปลอดภัยกว่าในการใช้วิธีremoveAll()นี้ ยอมรับชุดองค์ประกอบที่จะถูกลบออกจากรายการ คอลเลกชันจะต้องมีองค์ประกอบประเภทเดียวกับที่รายการเป้าหมายเก็บไว้ ไม่เช่นนั้นจะถูกโยนทิ้งClassCastExceptionไป เมธอดจะคืนค่าเป็นจริงหากรายการมีการเปลี่ยนแปลงอันเป็นผลมาจากการเรียกเมธอด
Подробный разбор класса ArrayList [Часть 1] - 11
ลบองค์ประกอบที่ไม่ได้อยู่ในคอลเลกชันที่ผ่าน:
public boolean retainAll(Collection< ?> c)
Подробный разбор класса ArrayList [Часть 1] - 12
สมมติว่าเรามีคอลเลกชัน:
List< String> listFirst = new ArrayList<>();
listFirst.add("White");
listFirst.add("Black");
listFirst.add("Red");
และประการที่สอง:
List< String> listSecond = new ArrayList<>();
listSecond.add("Green");
listSecond.add("Red");
listSecond.add("White");
จากนั้นหลังจากนั้นlistSecond.retainAll(listFirst)จะlistSecondยังคงอยู่:

"White"
"Red"
เนื่องจาก "สีเขียว" ถูกลบออกซึ่งไม่ได้อยู่ในlistFirst. แต่หลังจากlistSecond.removeAll(listFirst)นั้นก็listSecondจะยังคงอยู่:

"Green"
Удалorсь все элементы, которые есть в listFirst.
ไม่เป็นของคอลเลกชันที่ส่งผ่าน - หมายความว่าหากมีองค์ประกอบที่ไม่ได้อยู่ในคอลเลกชันที่ส่งผ่าน คุณจะต้องลบองค์ประกอบเหล่านั้นออกจากองค์ประกอบแรก (ซึ่งใช้วิธีการนั้น) เป็นของคอลเลกชันที่ถ่ายโอน - ดังนั้น หากมีองค์ประกอบในคอลเลกชันที่หนึ่งและที่สอง (ถ่ายโอน) รายการที่ซ้ำกันจากคอลเลกชันแรกจะถูกทำลาย
protected void removeRange(int fromIndex, int toIndex)
ลบองค์ประกอบทั้งหมดที่อยู่ระหว่างดัชนีเริ่มต้นที่ระบุ (รวม) และดัชนีที่ระบุสิ้นสุด (ไม่รวม) ออกจากรายการ เป็นที่น่าสังเกตว่าไม่สามารถเรียกวิธีการนี้บนวัตถุ ArrayList ได้โดยตรง หากต้องการใช้คุณจะต้องสืบทอดจากAbstractList/ArrayList. วิธีการนี้ยังใช้โดยวิธีอื่น (รายการย่อยซึ่งจะกล่าวถึงในภายหลัง)
public boolean removeIf(Predicate< ? super E> filter)
ลบองค์ประกอบออกจากคอลเลกชันตามภาคแสดงที่กำหนด ภาคแสดงนั้นเป็นฟังก์ชัน/อัลกอริธึม/เงื่อนไขบางอย่าง ซึ่งองค์ประกอบหนึ่งหรือหลายองค์ประกอบที่สอดคล้องกับเงื่อนไขที่กำหนดจะถูกลบออก Predicate— อินเทอร์เฟซการทำงาน (มีเพียงวิธีเดียวดังนั้นจึงสามารถใช้เป็นแลมบ์ดาได้) ทำงานบนหลักการ “ได้รับพารามิเตอร์เดียว - ส่งคืนบูลีน” โดยพื้นฐานแล้ว วิธีการนี้จะแทนที่การใช้งานจากอินเทอร์เฟซCollectionและใช้ "กลยุทธ์" ต่อไปนี้ โดยจะวนซ้ำองค์ประกอบต่างๆ และทำเครื่องหมายองค์ประกอบที่ตรงกับPredicate; จากนั้นจะดำเนินการเป็นครั้งที่สองเพื่อลบ (และเปลี่ยน) องค์ประกอบที่ถูกทำเครื่องหมายในการวนซ้ำครั้งแรก ลองใช้อินเทอร์เฟซPredicateที่จะคืนค่าเป็นจริงหากวัตถุทั้งสองเท่ากัน:
class SamplePredicate< T> implements Predicate< T>{
  T varc1;
  public boolean test(T varc){
     if(varc1.equals(varc)){
       return true;
  }
  return false;
  }
}
ในคลาสอื่น เรามาสร้าง ArrayList จากStringและอ็อบเจ็กต์ของคลาสของเราที่ใช้Predicate:
ArrayList< String> color_list = new ArrayList<> ();
SamplePredicate< String> filter = new SamplePredicate<> ();
varc1มาเขียน ค่า "White" ให้กับตัวแปร :
filter.varc1 = "White";
มาเพิ่มสองสามบรรทัดในรายการ:
color_list.add("White");
color_list.add("Black");
color_list.add("Red");
color_list.add("White");
color_list.add("Yellow");
color_list.add("White");
เรามาดำเนินการตามวิธีการในรายการremoveIfซึ่งเราจะส่งอ็อบเจ็กต์ของเราไปโดยมีเงื่อนไข:
color_list.removeIf(filter);
ด้วยเหตุนี้ แถวทั้งหมดที่มีค่า "สีขาว" จะถูกลบออกจากรายการ เนื่องจาก "ภาคแสดง" ของเราเปรียบเทียบแถวเหล่านั้นเพื่อความเท่าเทียมกัน รายการสุดท้าย: [ดำ แดง เหลือง]
Подробный разбор класса ArrayList [Часть 1] - 13
การแทนที่องค์ประกอบ
public E set(int index, E element)
แทนที่องค์ประกอบในตำแหน่งที่ระบุindexด้วยองค์ประกอบที่ส่งelementผ่าน ดัชนีจะต้องมากกว่าศูนย์และน้อยกว่าดัชนีขององค์ประกอบสุดท้าย มิฉะนั้นจะเกิดข้อIndexOutOfBoundsExceptionยกเว้น ไม่มีสำเนาของอาร์เรย์ภายในเกิดขึ้น เพียงแทนที่องค์ประกอบตามดัชนีที่ระบุ องค์ประกอบใหม่จะถูกแทรกเข้าไป เช่น เขียนทับค่า
Подробный разбор класса ArrayList [Часть 1] - 14
public void replaceAll(UnaryOperator<e> operator)
เปลี่ยนแปลงองค์ประกอบทั้งหมดของคอลเลกชัน (เป็นไปได้โดยมีเงื่อนไข) ส่วนใหญ่ใช้ร่วมกับlambdasหรือคลาสที่ไม่ระบุชื่อ (แต่เพื่อความชัดเจน ในตัวอย่างเราจะใช้คลาสที่ใช้อินเทอร์เฟซ) ที่ใช้อินเทอร์เฟซUnaryOperatorและกำหนดวิธีการของมัน ลองใช้อินเทอร์เฟซ:
class MyOperator< T> implements UnaryOperator< T>{
   T varc1;
   public T apply(T varc){
     return varc1;
  }
}
ในคลาสอื่น เรามาสร้าง ArrayList จากStringและอ็อบเจ็กต์ของคลาสของเราที่ใช้UnaryOperator:
ArrayList< String> color_list = new ArrayList<> ();
MyOperator< String> operator = new MyOperator<> ();
varc1มาเขียน ค่า "White" ให้กับตัวแปร :
operator.varc1 = "White";
มาเพิ่มสองสามบรรทัดในรายการ:
color_list.add("White");
color_list.add("Black");
color_list.add("Red");
color_list.add("White");
color_list.add("Yellow");
color_list.add("White");
ลองใช้วิธีการในรายการreplaceAllที่เราจะส่งวัตถุของเราไปoperator:
color_list.replaceAll(operator);
เป็นผลให้ค่าทั้งหมดในรายการถูกแทนที่ด้วย "สีขาว": [ขาว, ขาว, ขาว, ขาว, ขาว, ขาว] และนี่คือวิธีการลบช่องว่างทั้งหมดออกจากสตริงที่อยู่ในคอลเลกชัน:
ArrayList< String> list = new ArrayList<>(Arrays.asList("A   ", "  B  ", "C"));
list.replaceAll(String::trim);
วิธีการอื่น: คุณสามารถแปลงอาร์เรย์รายการ ArrayList เป็นอาร์เรย์ปกติได้โดยใช้วิธีการ:
public Object[] toArray()
หรือ
public < T> T[] toArray(T[] a)
- ที่นี่กำหนดประเภทของอาร์เรย์ที่ส่งคืนในruntime วิธีนี้จะช่วยให้:
  1. เร่งการดำเนินการบางอย่าง
  2. ส่งผ่านอาร์เรย์เป็นพารามิเตอร์ไปยังวิธีการที่ไม่โอเวอร์โหลดเพื่อยอมรับการรวบรวมโดยตรง
  3. การรวมรหัสตามคอลเลกชันใหม่เข้ากับรหัสเดิมที่ไม่รู้จักคอลเลกชัน
กลับวัตถุคัดลอกของอาร์เรย์:
public Object clone()
โปรดทราบว่าเมธอดนี้clone()ส่งคืนประเภท Object ดังนั้นหลังจากเรียกมันแล้ว คุณจะต้องส่งไปยังคลาสที่ต้องการ การโคลนนิ่งจะสร้างวัตถุอิสระใหม่ ตรวจสอบคอลเลกชันว่ามีวัตถุอยู่หรือไม่:
public boolean contains(Object o)
ตรวจสอบการมีอยู่ของวัตถุในรายการ (ภายในโดยใช้เมธอดเท่ากับของคลาส Object เช่น เปรียบเทียบการอ้างอิง) คืนค่าจริง/เท็จ ขึ้นอยู่กับผลลัพธ์ นอกเหนือจากการวนซ้ำตามปกติ คุณสามารถวนซ้ำ (เข้าถึงแต่ละองค์ประกอบ รวมถึงดำเนินการบางอย่าง) คอลเลกชันโดยใช้:
public void forEach(Consumer< ? super E> action)
นี่คือวิธีที่เราสามารถแสดงรายการของเรา:
List< Integer> numbers = new ArrayList<>(Arrays.asList(10, 20, 50, 100, -5));
numbers.forEach((number)-> System.out.println(number));
โดยไม่ต้องใช้ lambdas คุณต้องใช้คลาสที่ไม่ระบุชื่อและแทนที่ วิธี acceptอินเทอร์เฟซConsumer:
numbers.forEach(new Consumer< Integer>() {
  @Override
   public void accept(Integer integer) {
      System.out.println(integer);
          }
});
รับองค์ประกอบตามดัชนี:
public E get(int index)
ใช้สำหรับการเข้าถึงองค์ประกอบคอลเลกชันแบบสุ่ม ส่งคืนองค์ประกอบที่อยู่ในรายการที่ดัชนีที่ระบุ ถ้าindex < 0หรือ เป็นindex >=จำนวนองค์ประกอบสูงสุดในรายการ ข้อยกเว้นจะถูกส่งออกIndexOutOfBoundsExceptionไป นี่เป็นวิธีการพื้นฐานในการดึงองค์ประกอบจากรายการ และเวลาในการดึงองค์ประกอบตามดัชนีจะเท่ากันเสมอ ไม่ว่า ArrayList จะมีขนาดเท่าใดก็ตาม เนื่องจากกำลังเข้าถึงเซลล์อาร์เรย์ที่ระบุ ค้นหาดัชนีสำหรับวัตถุที่ระบุ:
public int indexOf(Object o);
public int lastIndexOf(Object o);
วิธีการส่งคืนดัชนีขององค์ประกอบแรก (เมื่อพบวัตถุที่กำหนดครั้งแรก) หรือเกิดขึ้นครั้งล่าสุด (เมื่อพบวัตถุที่กำหนดครั้งล่าสุด) ในรายการ หากไม่มีองค์ประกอบอยู่ในรายการ วิธีการจะส่งกลับ -1
Подробный разбор класса ArrayList [Часть 1] - 16
Подробный разбор класса ArrayList [Часть 1] - 17
ตรวจสอบคอลเลกชันสำหรับองค์ประกอบ:
public boolean isEmpty();
วิธีการคืนค่าเป็นจริงหากรายการว่างเปล่า (ดูว่าฟิลด์มีค่าเท่ากันหรือไม่size 0) มิฉะนั้นจะคืนค่าเป็นเท็จ หากรายการมีเพียงองค์ประกอบว่าง วิธีการจะส่งกลับเท็จ กล่าวอีกนัยหนึ่ง องค์ประกอบที่เป็นโมฆะจะถูกนำมาพิจารณาด้วยวิธีนี้ด้วย ค้นหาจำนวนองค์ประกอบในรายการ:
public int size();
ส่งกลับจำนวนองค์ประกอบในรายการ (ค่าฟิลด์ขนาด) จำนวนองค์ประกอบอาจแตกต่างจากความจุรายการ (ความจุ) รับตัววนซ้ำสำหรับรายการ:
public Iterator< E> iterator();
ส่งคืนตัววนซ้ำสำหรับรายการเพื่อใช้ในภายหลังในลูปหรือการประมวลผลอื่น ๆ ตัววนซ้ำใช้พฤติกรรมที่ล้มเหลวอย่างรวดเร็ว ถ้ามันทำงานผ่านคอลเลกชันและสังเกตเห็นการแก้ไขบางอย่าง (ที่ไม่ได้รับโดยใช้วิธีการวนซ้ำ) มันจะส่งข้อยกเว้นConcurrentModificationExceptionทันที ตัววนซ้ำมีสิ่งที่เรียกว่าmodification count. เมื่อตัววนซ้ำวนซ้ำคอลเลกชันหลังจากแต่ละรายการnext/hasNext/removeมันจะตรวจสอบตัวนับนี้ หากไม่ตรงกับสิ่งที่ตัววนซ้ำคาดว่าจะเห็น ก็จะเกิดข้อยกเว้น ฉันจะไม่พิจารณาตัววนซ้ำโดยละเอียดที่นี่
public ListIterator< E> listIterator() и public ListIterator< E> listIterator(int index)
ส่งคืนตัววนซ้ำรายการสำหรับรายการเพื่อใช้ในภายหลังในลูปหรือการประมวลผลอื่น ๆ อินเทอร์เฟซListIteratorขยายอินเทอร์เฟซIteratorสำหรับการสำรวจรายการแบบสองทางและการแก้ไของค์ประกอบ ในเวอร์ชันโอเวอร์โหลด คุณสามารถส่งผ่านดัชนีที่จะเริ่มต้น "การข้ามผ่าน" ได้ ดัชนีในกรณีนี้หมายถึงองค์ประกอบแรกที่วิธีการจะเริ่มทำงานnext()และเมื่อมีการเรียกใช้เมธอด การprevious()สำรวจเส้นทางจะเริ่มต้นจากองค์ประกอบภายใต้ดัชนี "ดัชนีที่ผ่าน - 1"
public Spliterator <E> spliterator()
Java 8 แนะนำรูปแบบใหม่ของการเชื่อมโยงล่าช้าและตัววนซ้ำที่ล้มเหลวอย่างรวดเร็วที่เรียกว่าตัววนซ้ำตัวคั่น ตัววนซ้ำตัวคั่นช่วยให้คุณสามารถวนซ้ำตามลำดับขององค์ประกอบได้ แต่จะมีการใช้ในลักษณะที่แตกต่างออกไป คุณสมบัติที่สำคัญที่สุดของ อินเทอร์ เฟซ Spliteratorคือความสามารถในการรองรับการวนซ้ำแบบขนานของแต่ละส่วนของลำดับขององค์ประกอบ และดังนั้นจึงการเขียนโปรแกรมแบบขนาน
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION