CodeGym /จาวาบล็อก /สุ่ม /Java.lang.คลาสจำนวนเต็ม
John Squirrels
ระดับ
San Francisco

Java.lang.คลาสจำนวนเต็ม

เผยแพร่ในกลุ่ม
ชนิดข้อมูล Java สามารถแบ่งตามเงื่อนไขออกเป็นสองบล็อก: ดั้งเดิมและการอ้างอิง (คลาส) มีข้อมูลพื้นฐานหลายประเภทใน Java เช่นจำนวนเต็ม ( byte , short , int , long ) ตัวเลขทศนิยม ( float , double ) ชนิดข้อมูลลอจิคัล ( boolean ) และชนิดข้อมูลอักขระ ( char ) คุณคงทราบแล้วว่าข้อมูลพื้นฐานแต่ละประเภทมีคลาส wrapper ของตัวเอง ชนิดข้อมูลอ้างอิงที่ "ตัด" หรือเปลี่ยนน้องชายคนเล็กดั้งเดิมในวัตถุ Java Integer เป็นคลาส wrapper สำหรับ bro ดั้งเดิมที่ชื่อ int จำนวนเต็มในภาษาอังกฤษหมายถึงจำนวนเต็ม อาจเป็นค่าบวก ลบ หรือ 0 น่าเสียดายที่ Integer ในภาษา Java ไม่ได้หมายถึงจำนวนเต็มใดๆ จำนวนเต็มใน Java คือจำนวนเต็มที่มีขนาด 32 บิต หากคุณต้องการตัวเลขที่มากขึ้น คุณสามารถใช้ตัวเลข Java Long ได้ พวกเขามี 64 บิตให้เลือก หากคุณโชคไม่ดีพอที่จะต้องการ Java จำนวนมากกว่านี้BigInteger ได้ครอบคลุมไว้ แล้ว

การทำงานกับจำนวนเต็ม

ในฐานะที่เป็นคลาส wrapper Integerจัดเตรียมวิธีการต่างๆ สำหรับการทำงานกับint ตลอดจนวิธีการต่างๆ ในการแปลงintเป็นStringและStringเป็นint คลาสนี้มีคอนสตรัคเตอร์สองตัว:
  • public Integer(int i)โดยที่iเป็นค่าดั้งเดิมในการเริ่มต้น อันนี้สร้าง วัตถุ จำนวนเต็มที่เริ่มต้นด้วยค่าint

  • Public Integer(String s ) พ่นNumberFormatException นี่คือการแสดงสตริงของค่าint ตัวสร้างนี้สร้าง วัตถุ จำนวนเต็มที่เริ่มต้นด้วย ค่า intที่ให้มาโดยการเป็นตัวแทนสตริง

การสร้างวัตถุจำนวนเต็ม

มีตัวเลือกการสร้างวัตถุจำนวน เต็มที่แตกต่างกัน หนึ่งในวิธีที่ใช้กันมากที่สุดคือวิธีที่ง่ายที่สุด นี่คือตัวอย่าง:
Integer myInteger = 5;
การกำหนดค่าเริ่มต้นของ ตัวแปร Integerในกรณีนี้จะคล้ายกับการกำหนดค่า เริ่มต้นของ ตัวแปร int ดั้งเดิม โดยวิธีการที่คุณสามารถเริ่มต้น ตัวแปร Integerด้วยค่าของint นี่คือตัวอย่าง:
int myInt = 5;
Integer myInteger = myInt;
System.out.println(myInteger);
ผลลัพธ์ที่นี่คือ:
5
ที่จริงแล้ว เราสามารถสังเกตการบรรจุอัตโนมัติได้ที่นี่ นอกจากนี้เรายังสามารถสร้าง วัตถุ จำนวนเต็มได้เหมือนกับวัตถุอื่น ๆ โดยใช้ตัวสร้างและ คำหลัก ใหม่ :
Integer myInteger = new Integer(5);
คุณสามารถดำเนินการกับ ตัวแปร Integerได้เช่นเดียวกับint (บวก ลบ คูณ หาร เพิ่ม ลดค่า) อย่างไรก็ตาม สิ่งสำคัญคือต้องจำไว้ว่าIntegerเป็นประเภทข้อมูลอ้างอิง และตัวแปรประเภทนี้อาจเป็นค่าว่างได้ ในกรณีนี้ควรงดเว้นจากการดำเนินการดังกล่าวจะดีกว่า
Integer myInteger1  = null;
Integer myInteger2 = myInteger1 + 5;
ที่นี่เราจะได้รับข้อยกเว้น:
ข้อยกเว้นในเธรด "main" java.lang.NullPointerException"

ค่าคงที่คลาสจำนวนเต็ม

คลาสIntegerจัดเตรียมค่าคงที่และวิธีการต่างๆ สำหรับการทำงานกับจำนวนเต็ม พวกเขาอยู่ที่นี่:
  • SIZEหมายถึงจำนวนบิตในระบบตัวเลขสองหลักที่ถูกครอบครองโดยประเภทint

  • BYTESคือจำนวนไบต์ในระบบตัวเลขสองหลักที่ถูกครอบครองโดยประเภทint

  • MAX_VALUEคือค่าสูงสุดที่ ประเภท intสามารถเก็บได้

  • MIN_VALUEคือค่าต่ำสุดที่ ประเภท intสามารถเก็บได้

  • TYPEส่งคืนวัตถุประเภทClassจากประเภทint

วิธีที่มีประโยชน์ที่สุดคลาสจำนวนเต็ม

ตอนนี้เรามาดูวิธีการที่ใช้มากที่สุดของคลาสInteger กันดีกว่า ฉันคิดว่าที่นิยมมากที่สุดคือวิธีการแปลงตัวเลขจากStringหรือในทางกลับกัน
  • int parseInt(String s) แบบคงที่วิธีการนี้จะแปลงStringเป็นint หากไม่สามารถแปลงได้NumberFormatExceptionจะถูกส่งออกไป

  • static int parseInt(String s , int radix)วิธีนี้ยังแปลง พารามิเตอร์ sเป็นint พารามิเตอร์Radixบ่งชี้ว่าระบบตัวเลขsถูกเขียนไว้ตั้งแต่แรก

นอกจากparseIntแล้ว ยังมี เมธอด valueOf ที่คล้ายกันมาก ในหลายรูปแบบ อย่างไรก็ตาม ผลลัพธ์ของvalueOfจะเป็นIntegerและparseIntจะเป็นint
  • static Integer valueOf(int i)ส่งคืนIntegerซึ่งมีค่าเป็นi ;

  • static Integer valueOf(String s)ทำงานเหมือนparseInt(String s)แต่ผลลัพธ์จะเป็นIntegerไม่ใช่int ;

  • static Integer valueOf(String s, int radix)ทำงานเหมือนกับparseInt(String s, int radix)แต่ผลลัพธ์คือIntegerไม่ใช่int

มีปัญหากับคลาส Integer หรือไม่? อ๋อ มี...

ดังนั้นจึงมีสองประเภทสำหรับจำนวนเต็ม (ที่พอดีกับ 32 บิต) ใน Java : intและInteger เพื่อให้เข้าใจถึงลักษณะเฉพาะของแต่ละรายการ เราจำเป็นต้องทราบข้อมูลต่อไปนี้เกี่ยวกับโมเดลหน่วยความจำ JVM: ทุกสิ่งที่คุณประกาศจะถูกเก็บไว้ใน Stack Memory (JVM Stack เฉพาะสำหรับแต่ละ Thread) หรือ Heap Space ประเภทดั้งเดิม ( int , long , float , boolean , double , char , byteฯลฯ ) จะถูกเก็บไว้ในหน่วยความจำ Stack ออบเจ็กต์และอาร์เรย์ทั้งหมดถูกจัดเก็บไว้ใน Heap Space การอ้างอิงถึงออบเจ็กต์และอาร์เรย์ที่จำเป็นสำหรับวิธีการเหล่านี้จะถูกจัดเก็บไว้ใน Stack ดังนั้น. ทำไมเราถึงสนใจ? คุณเห็นไหมว่า Stack มีขนาดเล็กกว่า Heap (a con) แต่จะจัดสรรค่าใน Stack ได้เร็วกว่า Heap (มืออาชีพ) มาก เริ่มต้นด้วยประเภทดั้งเดิมint มันกินพื้นที่ถึง 32 บิตพอดี นั่นคือ 32/8=4 ไบต์ เพราะมันเป็นประเภทดั้งเดิม ตอนนี้ลองพิจารณาInteger มันเป็นวัตถุที่มีค่าใช้จ่ายและการจัดแนวเพิ่มเติม ฉันใช้ไลบรารี jol เพื่อวัดขนาด:
public static void main(String[] args) {
 	System.out.println(ClassLayout.parseInstance(Integer.valueOf(1)).toPrintable());
}
และปรากฎว่ามีขนาดถึง 16 ไบต์:
java.lang.Integer วัตถุภายใน: ปิด SZ TYPE DESCRIPTION VALUE 0 8 (ส่วนหัวของวัตถุ: เครื่องหมาย) 0x000000748c90e301 (แฮช: 0x748c90e3; อายุ: 0) 8 4 (ส่วนหัวของวัตถุ: คลาส) 0x000492a0 12 4 int Integer.value 1 ขนาดอินสแตนซ์: 16 ไบต์
อะไร?! นั่นคือหน่วยความจำเพิ่มขึ้น 4 เท่า! แต่อย่าหยุดเพียงแค่นั้น ในฐานะนักพัฒนา Java ปกติแล้วเราจะไม่หยุดใช้จำนวนเต็มเพียงตัวเดียว สิ่งที่เราต้องการจริงๆคือใช้มันเยอะๆ เหมือนเป็นลำดับ. ตัวอย่างเช่นในอาร์เรย์ หรือรายการ. อาร์เรย์จะถูกจัดเก็บไว้ในฮีป เช่นเดียวกับรายการ ดังนั้นการจัดสรรจึงควรใช้เวลาประมาณเท่ากัน ขวา? แต่ถ้าเราจำเป็นต้องจัดสรรหน่วยความจำเพิ่มเติมล่ะ? ตรวจสอบว่าอาร์เรย์ของ ค่า int ดั้งเดิม 1,000 ค่าใช้พื้นที่เท่าใด:
public static void main(String[] args) {
    	int[] array = new int[1000];
    	for (int i = 0; i < 1000; i++) array[i] = i;                System.out.println(ClassLayout.parseInstance(array).toPrintable());
}
และผลลัพธ์คือ 4016 ไบต์:
OFF ค่าคำอธิบายประเภท SZ 0 8 (ส่วนหัวของวัตถุ: เครื่องหมาย) 0x0000000000000001 (ไม่เอนเอียง อายุ: 0) 8 4 (ส่วนหัวของวัตถุ: คลาส) 0x00006c38 12 4 (ความยาวอาร์เรย์) 1000 12 4 (ช่องว่างการจัดตำแหน่ง/ช่องว่างภายใน) 16 4000 int [I.<องค์ประกอบ> ไม่มี ขนาดอินสแตนซ์: 4016 ไบต์ การสูญเสียพื้นที่: 4 ไบต์ภายใน + 0 ไบต์ภายนอก = รวม 4 ไบต์
ตกลง มันสมเหตุสมผลดี เมื่อพิจารณาว่า int เดียวใช้เวลา 4 ไบต์ แล้วArrayList<Integer>ของ 1,000 Integers ล่ะ ? มาดูกัน:
public static void main(String[] args) {
	List<Integer> list = new ArrayList<>(1000);
	for (int i = 0; i < 1000; i++) list.add(i);
      System.out.println(GraphLayout.parseInstance(list).toFootprint());
}
และผลลัพธ์คือ 20,040 ไบต์ (เพิ่มอีก 4 เท่า!):
java.util.ArrayList@66d3c617d รอยเท้า: COUNT AVG SUM DESCRIPTION 1 4016 4016 [Ljava.lang.Object; 1,000 16 16000 java.lang.Integer 1 24 24 java.util.ArrayList 1002 20040 (ทั้งหมด)
ดังนั้นArrayList<Integer>จะใช้พื้นที่หน่วยความจำเพิ่มขึ้น 4 เท่า นั่นไม่ดีเลย แต่ถึงกระนั้น Lists ก็ง่ายกว่าเพราะเราสามารถเพิ่มและลบองค์ประกอบได้! โอ้จาวา… ทำไมคุณต้องใส่กล่องทุกอย่างด้วย! แต่ฉันลืมไปว่า Java นั้นยอดเยี่ยม และความยิ่งใหญ่ของมันอยู่ที่ไลบรารีโอเพ่นซอร์สที่มีอยู่มากมายที่เราสามารถใช้ได้! Trove4j ก็เป็นหนึ่งในนั้น มีTIntArrayListซึ่งมีข้อมูลint[] ภายใน มาวัดขนาดกัน:
public static void main(String[] args) {
	TIntList list = new TIntArrayList(1000);
	for (int i = 0; i < 1000; i++) list.add(i);
	System.out.println(GraphLayout.parseInstance(list).toFootprint());
}
และผลลัพธ์คือ 4040 ไบต์ (เกือบจะเหมือนกับเพียงแค่int[] !):
gnu.trove.list.array.TIntArrayList@7440e464d รอยเท้า: นับคำอธิบาย SUM เฉลี่ย 1 4016 4016 [I 1 24 24 gnu.trove.list.array.TIntArrayList 2 4040 (ทั้งหมด)
ดังนั้นในท้ายที่สุดแล้ว เราก็สามารถมีสิ่งที่ดีที่สุดจากทั้งสองโลกได้! รายการจำนวนเต็มที่ใช้พื้นที่น้อยกว่า 4 เท่า และสิ่งนี้ไม่เกี่ยวข้องกับอินสแตนซ์จำนวนเต็ม เฉพาะอินท์เอส เท่านั้น นักพัฒนา Java ของเราใส่ใจเรื่องหน่วยความจำจริงๆ… แต่เราก็ใส่ใจเรื่องประสิทธิภาพด้วย มีไลบรารี่ microbenchmarking ที่ยอดเยี่ยมซึ่งมีชื่อเรียบง่ายว่า jmh ซึ่งช่วยให้เราวัดประสิทธิภาพของโค้ดได้ ก่อนอื่น เรามาเปรียบเทียบประสิทธิภาพของการคำนวณผลรวมของจำนวนเต็มสุ่มสองตัว แบบชนิดบรรจุกล่องหรือไม่ก็ได้: การกำหนดค่าสำหรับ jmh เป็นดังนี้:
benchmark {
	configurations {
    	main {
        	warmups = 5 // number of warmup iterations
        	iterations = 50 // number of iterations
        	iterationTime = 500 // time in seconds per iteration
        	iterationTimeUnit = "ns" // time unit for iterationTime
เกณฑ์มาตรฐาน:
private static final Random random = new Random();

@Benchmark
public int testPrimitiveIntegersSum() {
	int a = random.nextInt();
	int b = random.nextInt();
	return a + b;
}

@Benchmark
public Integer testBoxedIntegersSum() {
	Integer a = random.nextInt();
	Integer b = random.nextInt();
	return a + b;
}
ผลลัพธ์:
main: test.SampleJavaBenchmark.testBoxedIntegersSum 5693337.344 ±(99.9%) 1198774.178 ops/s [เฉลี่ย] (ต่ำสุด, เฉลี่ย, สูงสุด) = (1092314.989, 5693337.344, 12001683.428), stdev = 242158 3.144 ซีไอ (99.9%): [4494563.166, 6892111.522] (ถือว่าการแจกแจงแบบปกติ) main: test.SampleJavaBenchmark.testPrimitiveIntegersSum 15295010.959 ±(99.9%) 2555447.456 ops/s [Average] (min, avg, max) = (4560097.059, 15295010.959, 24283809.447), stdev = 5162130.283 CI (99.9%): [12739563.502, 17850458.415] (ถือว่าการแจกแจงแบบปกติ)
ดังนั้น โดยเฉลี่ยแล้ว การจัดสรรและผลรวมของ int ดั้งเดิมจะเร็วกว่าของจำนวนเต็มชนิดบรรจุกล่องมากกว่าสองเท่า ตอนนี้เรามาเปรียบเทียบประสิทธิภาพของการสร้างและการคำนวณผลรวมของคอลเลกชัน (หรืออาร์เรย์ของจำนวนเต็ม 1,000 ints):
@Benchmark
public int testPrimitiveArray() {
	int[] array = new int[1000];
	for (int i = 0; i < 1000; i++) array[i] = i;
	int sum = 0;
	for (int x : array) sum += x;
	return sum;
}
11933.545 ops/s [Average]


@Benchmark
public int testBoxesArray() {
	Integer[] array = new Integer[1000];
	for (int i = 0; i < 1000; i++) array[i] = i;
	int sum = 0;
	for (int x : array) sum += x;
	return sum;
}
2733.312 ops/s [Average]


@Benchmark
public int testList() {
	List<Integer> list = new ArrayList<>(1000);
	for (int i = 0; i < 1000; i++) list.add(i);
	int sum = 0;
	for (int x : list) sum += x;
	return sum;
}
2086.379 ops/s [Average]


@Benchmark
public int testTroveIntList() {
	TIntList list = new TIntArrayList(1000);
	for (int i = 0; i < 1000; i++) list.add(i);
	int sum = 0;
	for (int i = 0; i < 1000; i++) sum += list.get(i);
	return sum;
}
5727.979 ops/s [Average]
ผลลัพธ์: อาร์เรย์ดั้งเดิมเร็วกว่าอาร์เรย์ของค่าชนิดบรรจุกล่องมากกว่า 4 เท่า ( Integer s); เร็วกว่าArrayListของค่าชนิดบรรจุกล่องเกือบหกเท่า ( Integer s); และเร็วเป็นสองเท่าของTIntArrayList (ซึ่งจริง ๆ แล้วตกแต่งอาร์เรย์ของ ints ดั้งเดิม) ดังนั้น หากคุณต้องการโครงสร้างข้อมูลเพื่อจัดเก็บชุดของค่าจำนวนเต็ม และขนาดของมันจะไม่เปลี่ยนแปลง ให้ใช้int[] ; หากขนาดกำลังจะเปลี่ยนแปลง - คุณอาจต้องการใช้ไลบรารี tove4j กับTIntArrayList และนี่คือจุดสิ้นสุดของเรียงความของฉัน โดยที่ฉันอธิบายข้อเสียของการใช้ประเภทจำนวนเต็ม มีวิธีการคงที่ที่น่าสนใจของIntegerซึ่งฉันควรพูดถึงก่อนที่จะเสร็จสิ้น public static Integer getInteger(String nm, int val)ไม่ได้ทำในสิ่งที่เราคิด แต่ดึง ค่า Integerของคุณสมบัติระบบ Valเป็นค่าเริ่มต้นในกรณีที่ไม่ได้ตั้งค่าคุณสมบัตินี้ public static String toBinaryString(int i)ส่งคืนสตริงที่มีการแทนค่าไบนารี่ของตัวเลข มีวิธีการในการดึงข้อมูลการเป็นตัวแทน based-16 ( toHexString ) และ based-8 ( toOctalString ) มีวิธีแยกวิเคราะห์String ลงในint แม้ว่าสตริงจะเป็นการแสดงตามฐานที่ไม่ใช่ 10 นี่คือตัวอย่างบางส่วน: Integer.parseInt("-FF", 16)ส่งกลับ -255 Integer.parseInt("+42", 10)ส่งกลับ 42 Integer.parseInt("1100110", 2)ส่งกลับ 102
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION