CodeGym/Blog Java/Ngẫu nhiên/Lớp Java.lang.Integer

Lớp Java.lang.Integer

Xuất bản trong nhóm
Các kiểu dữ liệu Java có thể được chia thành hai khối một cách có điều kiện: nguyên thủy và tham chiếu (các lớp). Có một số kiểu dữ liệu nguyên thủy trong Java, chẳng hạn như số nguyên ( byte , short , int , long ), số dấu phẩy động ( float , double ), kiểu dữ liệu logic ( boolean ) và kiểu dữ liệu ký tự ( char ). Có thể bạn đã biết rằng mỗi kiểu dữ liệu nguyên thủy có lớp trình bao bọc riêng. Một kiểu dữ liệu tham chiếu "bao bọc" hoặc biến em trai nguyên thủy của nó thành một đối tượng Java. Số nguyên là lớp bao bọc cho nguyên thủy của nó có tên int. Integer trong tiếng Anh có nghĩa là số nguyên. Chúng có thể dương, âm hoặc 0. Thật không may, Số nguyên trong Java không có nghĩa là bất kỳ số nguyên nào. Số nguyên trong java là một số nguyên vừa đủ 32 bit. Nếu bạn muốn số lượng lớn hơn, bạn có thể sử dụng số Java Long . Họ có 64 bit theo ý của họ. Nếu bạn không may mắn cần một số lượng lớn hơn nữa thì Java đã hỗ trợ BigInteger .

Làm việc với số nguyên

Là một lớp trình bao bọc, Integer cung cấp nhiều phương thức khác nhau để làm việc với int , cũng như một số phương thức để chuyển đổi int thành StringString thành int . Lớp này có hai hàm tạo:
  • public Integer(int i) , trong đó i là giá trị nguyên thủy để khởi tạo. Cái này tạo một đối tượng Integer được khởi tạo với giá trị int .

  • public Integer(String s) ném NumberFormatException . Đây s là biểu diễn chuỗi của giá trị int . Hàm tạo này tạo một đối tượng Integer được khởi tạo với giá trị int do biểu diễn chuỗi cung cấp .

Tạo đối tượng số nguyên

Có nhiều tùy chọn tạo đối tượng Integer khác nhau . Một trong những cách được sử dụng phổ biến nhất là cách dễ nhất. Đây là một ví dụ:

Integer myInteger = 5;
Việc khởi tạo biến Integer trong trường hợp này tương tự như việc khởi tạo biến int nguyên thủy . Nhân tiện, bạn có thể khởi tạo biến Integer với giá trị là int . Đây là một ví dụ:

int myInt = 5;
Integer myInteger = myInt;
System.out.println(myInteger); 
Đầu ra ở đây là:
5
Trên thực tế, ở đây chúng ta có thể quan sát quá trình đóng gói tự động. Ngoài ra, chúng ta có thể tạo một đối tượng Integer giống như bất kỳ đối tượng nào khác bằng cách sử dụng hàm tạo và từ khóa mới :

Integer myInteger = new Integer(5);
Bạn có thể thực hiện với biến Integer giống như với int (cộng, trừ, nhân, chia, tăng, giảm). Tuy nhiên, điều quan trọng cần nhớ là Số nguyên là kiểu dữ liệu tham chiếu và biến thuộc loại này có thể có giá trị rỗng. Trong trường hợp này, tốt hơn là nên kiềm chế những hoạt động như vậy.

Integer myInteger1  = null;
Integer myInteger2 = myInteger1 + 5; 
Ở đây chúng ta sẽ có một ngoại lệ:
Ngoại lệ trong chuỗi "chính" java.lang.NullPointerException"

Hằng số lớp số nguyên

Lớp Integer cung cấp nhiều hằng số và phương thức khác nhau để làm việc với số nguyên. Họ đây rồi:
  • SIZE có nghĩa là số bit trong hệ thống số có hai chữ số được chiếm bởi kiểu int

  • BYTES là số byte trong hệ thống số có hai chữ số được chiếm bởi loại int

  • MAX_VALUE là giá trị lớn nhất mà kiểu int có thể chứa

  • MIN_VALUE là giá trị nhỏ nhất mà kiểu int có thể chứa

  • TYPE trả về một đối tượng kiểu Class từ kiểu int

Lớp số nguyên các phương thức hữu ích nhất

Bây giờ chúng ta hãy xem qua các phương thức được sử dụng nhiều nhất của lớp Integer . Tôi cho rằng phổ biến nhất trong số đó là các phương pháp chuyển đổi một số từ String hoặc ngược lại.
  • static int parsInt(String s) phương thức này chuyển đổi String thành int . Nếu không thể chuyển đổi, NumberFormatException sẽ bị ném ra.

  • static int parsInt(String s, int radix) phương thức này cũng chuyển đổi tham số s thành int . Tham số cơ số cho biết hệ thống số s ban đầu được viết.

Ngoài ParseInt , còn có một phương thức valueOf rất giống nhau ở một số biến thể. Tuy nhiên, kết quả của valueOf sẽ là IntegerextractInt sẽ là int .
  • static Integer valueOf(int i) trả về một Integer có giá trị là i ;

  • static Integer valueOf(String s) hoạt động giống như parseInt(String s) , nhưng kết quả sẽ là Integer , không phải int ;

  • static Integer valueOf(String s, int radix) hoạt động tương tự như extractInt(String s, int radix) , nhưng kết quả là Integer , không phải int .

Có vấn đề gì với lớp Integer không? Ồ vâng, có…

Vì vậy, có hai loại số nguyên (vừa với 32 bit) trong Java: intInteger . Để hiểu chi tiết cụ thể của từng loại, chúng ta cần biết những điều sau đây về mô hình bộ nhớ JVM: mọi thứ bạn khai báo đều được lưu trữ trong Bộ nhớ ngăn xếp (Ngăn xếp JVM dành riêng cho từng Chủ đề) hoặc Không gian Heap. Các kiểu nguyên thủy ( int , long , float , boolean , double , char , byte , v.v.) được lưu trữ trong bộ nhớ Stack. Tất cả các đối tượng và mảng được lưu trữ trong Heap Space. Các tham chiếu đến các đối tượng và mảng cần thiết cho các phương thức này được lưu trữ trong Stack. Vì thế. Tại sao chúng ta quan tâm? Chà, bạn thấy đấy, Stack nhỏ hơn Heap (một nhược điểm), nhưng việc phân bổ các giá trị trong Stack nhanh hơn nhiều so với trong Heap (một chuyên gia). Hãy bắt đầu với kiểu nguyên thủy int . Nó chiếm chính xác 32 bit. Đó là 32/8=4 byte. Bởi vì nó là một loại nguyên thủy. Bây giờ, hãy xem xét Integer . Nó là một đối tượng, có thêm chi phí và sự sắp xếp. Tôi đã sử dụng thư viện jol để đo kích thước của nó:

public static void main(String[] args) {
 	System.out.println(ClassLayout.parseInstance(Integer.valueOf(1)).toPrintable());
}
và hóa ra nó chiếm tới 16 byte:
Nội bộ đối tượng java.lang.Integer: TẮT GIÁ TRỊ MÔ TẢ LOẠI SZ 0 8 (tiêu đề đối tượng: đánh dấu) 0x000000748c90e301 (băm: 0x748c90e3; tuổi: 0) 8 4 (tiêu đề đối tượng: lớp) 0x000492a0 12 4 int Số nguyên.giá trị 1 Kích thước phiên bản: 16 byte
Cái gì?! Đó là bộ nhớ gấp 4 lần! Nhưng chúng ta đừng dừng lại ở đó. Là nhà phát triển Java, chúng tôi thường không ngừng sử dụng một số nguyên duy nhất. Điều chúng tôi thực sự muốn là sử dụng thật nhiều chúng. Giống như theo một trình tự. Ví dụ, trong một mảng. Hoặc một Danh sách. Mảng được lưu trữ trong Heap, giống như Danh sách. Vì vậy, việc phân bổ sẽ mất khoảng thời gian tương tự. Phải? Nhưng nếu chúng ta cần phân bổ thêm bộ nhớ thì sao? Hãy kiểm tra xem một mảng gồm 1000 giá trị int nguyên thủy chiếm bao nhiêu dung lượng:

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());
}
Và kết quả là 4016 byte:
TẮT GIÁ TRỊ MÔ TẢ LOẠI SZ 0 8 (tiêu đề đối tượng: dấu) 0x0000000000000001 (không thiên vị; tuổi: 0) 8 4 (tiêu đề đối tượng: lớp) 0x00006c38 12 4 (độ dài mảng) 1000 12 4 (khoảng cách căn chỉnh/đệm) 16 4000 int [I. N/A Kích thước phiên bản: 4016 byte Mất không gian: 4 byte bên trong + 0 byte bên ngoài = tổng cộng 4 byte
Được rồi, điều đó cũng có lý, vì một int đơn lẻ có 4 byte. Thế còn ArrayList<Integer> của 1000 Số nguyên thì sao ? Chúng ta hãy có một cái nhìn:

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());
}
Và kết quả là 20040 byte (một lần nữa, gấp 4 lần!):
Dấu chân java.util.ArrayList@66d3c617d: ĐẾM MÔ TẢ TỔNG TRUNG BÌNH 1 4016 4016 [Ljava.lang.Object; 1000 16 16000 java.lang.Integer 1 24 24 java.util.ArrayList 1002 20040 (tổng cộng)
Vì vậy, ArrayList<Integer> chiếm dung lượng bộ nhớ nhiều hơn 4 lần. Điều đó không tốt. Tuy nhiên, Danh sách vẫn dễ dàng hơn vì chúng ta có thể thêm và xóa các phần tử! Ôi Java… Tại sao bạn lại cần đóng hộp mọi thứ?! Nhưng tôi quên mất, Java rất tuyệt và sự tuyệt vời của nó nằm ở sự phong phú của các thư viện nguồn mở mà chúng ta có thể sử dụng! Trove4j là một trong số đó. Nó có TIntArrayList bên trong có dữ liệu int[] . Hãy đo kích thước của nó:

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());
}
Và kết quả là 4040 byte (gần giống như int[] !):
dấu chân gnu.trove.list.array.TIntArrayList@7440e464d: ĐẾM MÔ TẢ TỔNG TRUNG BÌNH 1 4016 4016 [Tôi 1 24 24 gnu.trove.list.array.TIntArrayList 2 4040 (tổng cộng)
Vì vậy, cuối cùng, chúng ta có thể có được điều tốt nhất của cả hai thế giới! Danh sách các số nguyên chiếm ít không gian hơn 4 lần. Và điều này không liên quan đến các trường hợp Integer . Chỉ int s. Các nhà phát triển Java chúng tôi thực sự quan tâm đến bộ nhớ… Nhưng chúng tôi cũng quan tâm đến hiệu suất. Có một thư viện đo điểm chuẩn vi mô tuyệt vời với cái tên khiêm tốn jmh cho phép chúng tôi đo lường hiệu suất của mã. Trước tiên, hãy so sánh hiệu suất tính tổng của hai số nguyên ngẫu nhiên, được đóng hộp hoặc không: Cấu hình cho jmh như sau:

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
Các điểm chuẩn:

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;
}
Kết quả:
chính: test.SampleJavaBenchmark.testBoxedIntegersSum 5693337.344 ±(99,9%) 1198774.178 hoạt động/giây [Trung bình] (tối thiểu, trung bình, tối đa) = (1092314.989, 5693337.344, 12001683.428), stdev = 2421583.144 CI (99,9%): [4494563.166, 6892111.522] (giả định phân phối chuẩn) chính: test.SampleJavaBenchmark.testPrimitiveIntegersSum 15295010,959 ±(99,9%) 2555447,456 hoạt động/giây [Trung bình] (tối thiểu, trung bình, tối đa) = (4560097.059, 15295010.959, 24283809.447), stdev = 5162130.283 CI (99,9%): [12739563.502, 17850458.415] (giả định phân phối bình thường)
Vì vậy, trung bình, việc phân bổ và tổng các số nguyên nguyên thủy nhanh hơn gấp đôi so với các Số nguyên được đóng hộp. Bây giờ, hãy so sánh hiệu suất tạo và tính tổng của các bộ sưu tập (hoặc mảng 1000 int Số nguyên):

@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]
Kết quả: mảng nguyên thủy nhanh hơn 4 lần so với mảng giá trị được đóng hộp ( Integer s); nhanh hơn gần sáu lần so với ArrayList của các giá trị được đóng hộp ( Integer s); và nhanh gấp đôi so với TIntArrayList (thực sự trang trí một mảng các số nguyên nguyên thủy). Do đó, nếu bạn cần cấu trúc dữ liệu để lưu trữ tập hợp các giá trị số nguyên và kích thước của nó sẽ không thay đổi, hãy sử dụng int [] ; nếu kích thước sắp thay đổi — bạn có thể muốn sử dụng thư viện tove4j với TIntArrayList . Và đây là phần cuối của bài luận, nơi tôi giải thích những nhược điểm của việc sử dụng kiểu Số nguyên . Có một số phương thức tĩnh thú vị của Integer mà tôi nên nói đến trước khi kết thúc. public static Integer getInteger(String nm, int val) không làm những gì người ta có thể nghĩ mà lấy ra giá trị Integer của thuộc tính hệ thống. Val là mặc định trong trường hợp thuộc tính này không được đặt. public static String toBinaryString(int i) trả về một Chuỗi có biểu diễn nhị phân của một số. Có các phương pháp để truy xuất các biểu diễn dựa trên 16 ( toHexString ) và dựa trên 8 ( toOctalString ). Có một phương pháp để phân tích Chuỗi thành int . Ngay cả khi chuỗi là biểu diễn dựa trên cơ số không phải là 10. Dưới đây là một số ví dụ: Integer.parseInt("-FF", 16) trả về -255 Integer.parseInt("+42", 10) trả về 42 Integer.parseInt("1100110", 2) trả về 102
Bình luận
  • Phổ biến
  • Mới
Bạn phải đăng nhập để đăng nhận xet
Trang này chưa có bất kỳ bình luận nào