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 String và String 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à:
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ệ:
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.
-
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: int và Integer . Để 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:
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:
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!):
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[] !):
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ả:
@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