คุณสมบัติความยาวของอาเรย์กำหนดไว้ที่ไหน?


263

เราสามารถกำหนดความยาวของการArrayList<E>ใช้วิธีการสาธารณะsize()เช่น

ArrayList<Integer> arr = new ArrayList(10);
int size = arr.size();

ในทำนองเดียวกันเราสามารถกำหนดความยาวของArrayวัตถุโดยใช้lengthคุณสมบัติ

String[] str = new String[10];
int size =  str.length;

ในขณะที่size()วิธีการที่ArrayListถูกกำหนดไว้ในArrayListชั้นเรียนซึ่งเป็นlengthคุณสมบัติของการArrayกำหนดที่?


ในแง่ของการตั้งคำถามฉันขอแนะนำให้คุณตั้งคำถามไว้ว่า ก่อนคำอธิบายทั้งหมดเพื่อป้องกันไม่ให้โพสต์ของคุณมีเสียงเหมือนบทแนะนำของผู้เริ่มต้น
NoName

คำตอบ:


250

อาร์เรย์มีวัตถุพิเศษใน java พวกเขามีแอตทริบิวต์ที่เรียบง่ายที่มีชื่อซึ่งเป็นlengthfinal

ไม่มี "คำจำกัดความของคลาส" ของอาร์เรย์ (คุณไม่สามารถหาได้ในไฟล์. class ใด ๆ ) พวกมันเป็นส่วนหนึ่งของภาษานั้น ๆ

10.7 สมาชิกอาเรย์

สมาชิกประเภทอาเรย์ต่าง ๆ ดังต่อไปนี้:

  • public finalข้อมูลlengthซึ่งมีจำนวนขององค์ประกอบของอาร์เรย์ lengthอาจเป็นบวกหรือเป็นศูนย์
  • publicวิธีการcloneซึ่งแทนที่วิธีการที่มีชื่อเดียวกันในชั้นเรียนObjectและพ่นไม่มีข้อยกเว้นการตรวจสอบ ประเภทการกลับมาของcloneวิธีการของชนิดอาร์เรย์คือT[]T[]

    โคลนของอาร์เรย์หลายมิตินั้นตื้นซึ่งจะกล่าวว่ามันสร้างเพียงอาร์เรย์ใหม่เพียงเส้นเดียว มีการแชร์หัวข้อย่อย

  • สมาชิกทุกคนได้รับมรดกมาจากชั้นObject; วิธีการเดียวของObjectที่ไม่ได้รับการถ่ายทอดเป็นcloneวิธีการ

แหล่งข้อมูล:


84
โปรดทราบว่าArrayList.size()ยังมีจำนวนของวัตถุที่จัดเก็บจริงในอาร์เรย์ในขณะที่myArray.length( []) ให้ "ความจุ" นั่นคือถ้าmyArray = new int[10];มันส่งคืน 10 ไม่ใช่จำนวนวัตถุที่คุณใส่ในอาร์เรย์
wmorrison365

1
@Colin วัตถุอาร์เรย์มีความพิเศษอย่างไรฉันหมายถึงว่าทำไมนักออกแบบจึงต้องทำให้เป็นพิเศษและทำไมไม่ให้ไฟล์คลาสของอาร์เรย์
Vikas Verma

5
@VikasVerma ทำไมอาร์เรย์ถึงไม่ชอบวัตถุ เพราะประวัติศาสตร์ เมื่อ Java ได้รับการออกแบบความพยายามในการสร้างนวัตกรรมทางภาษาส่วนใหญ่จะล้มเหลวเมื่อไม่เหมือนกับ C ในรูปแบบและไวยากรณ์ ดังนั้น C ++, Objective-C, และ Java จึงเป็นหนึ่งในไม่กี่ภาษาที่จะหลบหนีความสับสนในยุคนั้น Java ได้รับการออกแบบอย่างมีสติเพื่อให้มีเครื่องหมายปีกกาแบบดั้งเดิมและอาร์เรย์ธรรมดาเพื่อให้คุ้นเคยกับโปรแกรมเมอร์หลักของวัน ดูการสัมภาษณ์กับ James Gosling และกลุ่มคนอื่น ๆ ของดวงอาทิตย์ บางคนยึดติดกับ Collections สำหรับ OOP บริสุทธิ์และหลีกเลี่ยงอาร์เรย์ธรรมดา
Basil Bourque

1
@VikasVerma ในบางจุด java ต้องสร้างขึ้นด้วยเทคโนโลยีระดับล่าง หากไม่มี java คุณไม่สามารถสร้างได้ด้วย java คุณต้องใช้ C ++ (หรืออย่างอื่น แต่ C ++ ในกรณีนี้) เพื่อสร้างการคอมไพล์ดั้งเดิมสำหรับส่วนที่เหลือของ java เพื่อให้บริบทสำหรับการมีอยู่ของตัวเอง คุณไม่สามารถมีคลาสสำหรับทุกสิ่งได้ในที่สุดโดยไม่ต้องกดปุ่มด้านล่างสุดที่ซึ่งคุณใช้รหัสใน C ++ คุณจะสร้างอาเรย์ใน java ได้อย่างไร? หากคุณไม่สามารถใช้ a Listเพราะใช้อาร์เรย์ในการใช้งาน
Alexander Bird

ถ้าคุณต้องการที่จะตอบมันตามที่เป็นอยู่แล้วstackoverflow.com/a/50506451/1059372
ยูจีน

114

มันเป็น "พิเศษ" โดยทั่วไปกับการเรียนการสอน bytecode arraylengthของตัวเอง: ดังนั้นวิธีนี้:

public static void main(String[] args) {
    int x = args.length;
}

ถูกรวบรวมเป็น bytecode ดังนี้:

public static void main(java.lang.String[]);
  Code:
   0:   aload_0
   1:   arraylength
   2:   istore_1
   3:   return

ดังนั้นจึงไม่สามารถเข้าถึงได้เหมือนเป็นฟิลด์ปกติ แน่นอนถ้าคุณพยายามที่จะรับมันราวกับว่ามันเป็นสนามปกติเช่นนี้มันล้มเหลว:

// Fails...
Field field = args.getClass().getField("length");
System.out.println(field.get(args));

น่าเสียดายที่คำอธิบาย JLS ของแต่ละประเภทอาเรย์ที่มีเขตข้อมูลสุดท้ายสาธารณะlengthเป็นสิ่งที่ทำให้เข้าใจผิด :(


1
ผมจำไม่ได้ว่าพูดโดย Albert Einstein แต่สิ่งที่มันบอกว่าเป็น "คนเข้าใจสิ่งที่ดีมากสามารถอธิบายสิ่งที่อยู่ในวิธีที่ง่ายมาก" ผมคิดว่ามันเหมาะกับคุณได้เป็นอย่างดี :)
JAVA

@Jon Skeet วัตถุอาร์เรย์มีความพิเศษอย่างไรฉันหมายถึงว่าทำไมนักออกแบบจึงต้องทำให้เป็นพิเศษและทำไมไม่ให้ไฟล์คลาสของอาร์เรย์
Vikas Verma

2
@VikasVerma: คิดเกี่ยวกับขนาดของวัตถุอาร์เรย์ ประเภทอื่น ๆ ทั้งหมดมีขนาดคงที่ - ทุกอินสแตนซ์มีขนาดเดียวกันในขณะที่อาร์เรย์แตกต่างกันไปตามความยาว นั่นเป็นเพียงตัวอย่างเดียว หากคุณคิดว่าคุณสามารถบรรลุผลลัพธ์เดียวกันโดยไม่ใช้อะไรเป็นพิเศษคุณคิดว่าฟิลด์ของคลาสอาเรย์จะเป็นอย่างไร คุณจะแสดงint[]อย่างไรเมื่อยาชื่อสามัญไม่สามารถใช้กับชนิดดั้งเดิมได้ (และ heck, generics ไม่ได้มีอยู่เป็นเวลานาน) คุณสามารถหนีไปได้โดยไม่ต้องใช้อาร์เรย์โดยใช้รายการที่เชื่อมโยงสำหรับคอลเลกชันทั้งหมด แต่มันจะน่ากลัวสำหรับประสิทธิภาพ
Jon Skeet

@ JonSkeet แล้วประเภทของ StringBuffer จะมีขนาดคงที่หรือไม่ ใช่ฉันคิดเกี่ยวกับยาชื่อสามัญ แต่คุณชี้ให้เห็นก่อนที่ฉันจะขอขอบคุณสำหรับมัน
Vikas Verma

@VikasVerma: StringBufferชั้นเรียนของตัวเองใช่ - เพราะมันมีการอ้างอิงถึงchar[](หรืออย่างน้อยก็ฉันไม่รู้ว่ามันยังคงทำนอกมือ) ดังนั้นในขณะที่ a StringBuilderรับผิดชอบหน่วยความจำเพิ่มเติมขนาดและเลย์เอาต์ของมันจะถูกแก้ไขทันที
Jon Skeet

18

มันกำหนดไว้ในข้อกำหนดภาษาจาวา :

สมาชิกประเภทอาเรย์ต่าง ๆ ดังต่อไปนี้:

  • public finalข้อมูลlengthซึ่งมีจำนวนขององค์ประกอบของอาร์เรย์ lengthอาจเป็นบวกหรือเป็นศูนย์

เนื่องจากมีประเภทอาเรย์จำนวนไม่ จำกัด (สำหรับทุกคลาสมีประเภทอาเรย์ที่สอดคล้องกันและจากนั้นมีอาเรย์หลายมิติ) จึงไม่สามารถนำไปใช้ในไฟล์คลาสได้ JVM ต้องทำทันที


15

แม้ว่านี่จะไม่ใช่คำตอบสำหรับคำถามโดยตรง แต่มันก็เป็นส่วนเสริมของอาร์กิวเมนต์.lengthvs .size()ฉันกำลังค้นคว้าสิ่งที่เกี่ยวข้องกับคำถามนี้ดังนั้นเมื่อฉันเจอมันฉันสังเกตเห็นว่าคำจำกัดความที่ให้ไว้ที่นี่

ความยาวสนามสุดท้ายประชาชนซึ่งมีจำนวนขององค์ประกอบของอาร์เรย์

ไม่ถูกต้อง

ความยาวของเขตข้อมูลประกอบด้วยจำนวนของสถานที่ที่มีอยู่เพื่อใส่ส่วนประกอบไม่ใช่จำนวนขององค์ประกอบที่มีอยู่ในอาร์เรย์ ดังนั้นจึงแสดงถึงหน่วยความจำทั้งหมดที่มีอยู่ซึ่งจัดสรรให้กับอาร์เรย์นั้นไม่ใช่จำนวนหน่วยความจำที่เต็มไป

การจัดสรรหน่วยความจำ Array

ตัวอย่าง:

static class StuffClass {
    int stuff;
    StuffClass(int stuff) {
        this.stuff = stuff;
    }
}

public static void main(String[] args) {

    int[] test = new int[5];
    test[0] = 2;
    test[1] = 33;
    System.out.println("Length of int[]:\t" + test.length);

    String[] test2 = new String[5];
    test2[0] = "2";
    test2[1] = "33";    
    System.out.println("Length of String[]:\t" + test2.length);

    StuffClass[] test3 = new StuffClass[5];
    test3[0] = new StuffClass(2);
    test3[1] = new StuffClass(33);
    System.out.println("Length of StuffClass[]:\t" + test3.length);         
}

เอาท์พุท:

Length of int[]:        5
Length of String[]:     5
Length of StuffClass[]: 5

อย่างไรก็ตาม.size()คุณสมบัติของการArrayListให้จำนวนองค์ประกอบในรายการ:

ArrayList<Integer> intsList = new ArrayList<Integer>();
System.out.println("List size:\t" + intsList.size());
intsList.add(2);
System.out.println("List size:\t" + intsList.size());
intsList.add(33);
System.out.println("List size:\t" + intsList.size());

เอาท์พุท:

List size:  0
List size:  1
List size:  2

1
มันถูกต้องเนื่องจากองค์ประกอบทั้งหมดจะเริ่มต้นเป็นศูนย์ อาร์เรย์ต้องไม่ "ว่างเปล่า"
Guido

นั่นคือสิ่งที่ฉันพูด มันไม่ถูกต้อง มันยังคงมีความยาว 5 แม้ว่าจะไม่มีการเพิ่มอะไรเข้าไปในอาร์เรย์ ดังนั้นมันจึงไม่ "แน่นอน" มีจำนวนองค์ประกอบในอาร์เรย์ ความคิดเห็นของคุณเป็นเพียงคำตอบเพิ่มเติมจากฉันไม่ใช่เหตุผลที่ทำให้มันไม่ถูกต้อง
nem035

อาจเป็น "ไม่ถูกต้อง" หากคุณพยายามแยกความแตกต่างระหว่างnullองค์ประกอบที่ไม่ใช่ค่าว่าง แต่ความแตกต่างไม่ได้ผล ท้ายที่สุดแล้ว, size()ของ (พูด) a Listอาจรวมถึงnullค่าเกินไป
สตีเฟ่นซี

ใช่แล้วประเด็นของฉันก็คือว่ามันsizeทำงานแบบไดนามิกในขณะที่lengthเป็นคุณสมบัติคงที่ ... ความจริงที่ว่าพื้นที่ว่างที่ยังไม่ได้บรรจุในอาเรย์ได้รับการกำหนดค่าเริ่มต้นเป็น " ไม่ใช่ค่า " (ขึ้นอยู่กับประเภท) ไม่ขัดแย้งกับประเด็นนี้
nem035

5

เป็นเขตข้อมูลสุดท้ายสาธารณะซึ่งมีจำนวนส่วนประกอบของอาร์เรย์ (ความยาวอาจเป็นบวกหรือเป็นศูนย์)

อาร์เรย์จึงมีเขตข้อมูลสาธารณะและวิธีการเดียวกันกับคลาสต่อไปนี้:

class A implements Cloneable, java.io.Serializable {
    public final int length = X;
    public Object clone() {
        try {
            return super.clone();
        } catch (CloneNotSupportedException e) {
            throw new InternalError(e.getMessage());
        }
    }
}

ข้อมูลเพิ่มเติมได้ที่

10.7 สมาชิกอาเรย์

http://java.sun.com/docs/books/jls/second_edition/html/arrays.doc.html


0

เพื่อตอบคำถามตามที่เป็นอยู่คุณสมบัติความยาวของอาเรย์กำหนดไว้ที่ไหน? Object headerในพิเศษ

ง่ายต่อการดูผ่านJOL

 int [] ints = new int[23];
 System.out.println(ClassLayout.parseInstance(ints).toPrintable());

หนึ่งในบรรทัดจากเอาต์พุตนี้จะเป็น:

OFFSET  SIZE      TYPE DESCRIPTION
16       4        (object header)   17 00 00 00 (00010111 00000000 00000000 00000000) (23)

โดยปกติวัตถุที่มีสองหัว (เครื่องหมายและ Klass) อาร์เรย์มีอีกหนึ่งที่มักจะครอบครอง4 bytesความยาวตามที่เป็นsizeint


-1

ความยาวของคำหลักทำหน้าที่เหมือนข้อมูลที่กำหนดไว้ เมื่อใช้ในอาเรย์เราสามารถใช้มันเพื่อเข้าถึงจำนวนอิลิเมนต์ในอาเรย์ เกี่ยวกับ String [] เราสามารถเรียกใช้ length () วิธีการที่กำหนดไว้ในคลาส String เกี่ยวกับ ArrayList เราสามารถใช้ size () วิธีการที่กำหนดไว้ใน ArrayList โปรดทราบว่าเมื่อสร้างรายการอาร์เรย์ด้วย ArrayList <> (ความจุ) ขนาดเริ่มต้น () ของรายการอาร์เรย์นี้จะเป็นศูนย์เนื่องจากไม่มีองค์ประกอบ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.