CodeGym /Java Blog /Toto sisi /Java.lang.Integer 類
John Squirrels
等級 41
San Francisco

Java.lang.Integer 類

在 Toto sisi 群組發布
Java 資料型別可以有條件地分為兩個區塊:原始資料型別和引用(類別)。Java中有多種基本資料型,例如整數(byteshortintlong)、浮點數(floatdouble)、邏輯資料型別(boolean)和字元資料型別(char)。您可能已經知道每種基本資料類型都有自己的包裝類別。一種引用資料類型,將其原始兄弟「包裝」或轉變為 Java 物件。Integer 是其名為 int 的原始兄弟的包裝類別。Integer在英語中的意思是整數。它們可以是正數、負數或 0。不幸的是,Java 中的 Integer 並不表示任何整數。java中的整數是32位元的整數。如果您想要更大的數字,歡迎使用 Java Long數字。他們有 64 位元可供使用。如果您不幸需要更大的數字,Java 可以為您提供BigInteger

使用整數

作為包裝類,Integer提供了各種使用int 的方法,以及許多將int轉換為StringString轉換為int的方法。此類別有兩個建構函數:
  • public Integer(int i),其中i是要初始化的原始值。這個創建了一個用int值初始化的Integer物件。

  • public Integer(String s)拋出NumberFormatException。這裡s是int值的字串表示形式。此構造函數建立一個Integer對象,該對象使用字串表示形式提供的int值進行初始化。

整數物件創建

有不同的Integer物件建立選項。最常用的一種也是最簡單的一種。這是一個例子:
Integer myInteger = 5;
這種情況下Integer變數 的初始化與原始 int變數的初始化類似。順便說一句,您可以使用int的值初始化Integer變數。這是一個例子:
int myInt = 5;
Integer myInteger = myInt;
System.out.println(myInteger);
這裡的輸出是:
5
事實上,在這裡我們可以觀察到自動打包。我們也可以使用建構函式和new關鍵字來建立一個Integer對象,就像任何其他對像一樣:
Integer myInteger = new Integer(5);
您可以像使用int一樣 使用Integer變數(加法、減、乘、除、遞增、遞減)。但是,請務必記住,Integer是一種引用資料類型,並且該類型的變數可以為 null。在這種情況下,最好不要進行此類操作。
Integer myInteger1  = null;
Integer myInteger2 = myInteger1 + 5;
這裡我們會得到一個異常:
線程“main”中的異常 java.lang.NullPointerException”

整數類常數

Integer類別提供了用於處理整數的各種常數和方法他們來了:
  • SIZE表示int型別所佔用的兩位數係統中的位數

  • BYTES是int型別佔用的兩位數係統中的位元組數

  • MAX_VALUE是int型別可以容納的最大值

  • MIN_VALUE是int型別可以容納的最小值

  • TYPEint類型傳回Class類型的對象

整數類別最有用的方法

現在讓我們來看看Integer類別最常用的方法。我認為其中最受歡迎的是從String轉換數字的方法,反之亦然。
  • static 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)傳回一個值為i的Integer

  • 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類別有什麼問題嗎?哦,是的,有…

因此,Java 中有兩種整數類型(適合 32 位元):intInteger。要了解它們的具體情況,我們需要了解有關 JVM 記憶體模型的以下資訊:您聲明的所有內容都儲存在堆疊記憶體(特定於每個執行緒的 JVM 堆疊)或堆疊空間中。基本型別(intlongfloatbooleandoublecharbyte等)儲存在堆疊記憶體中。所有物件和陣列都儲存在堆空間中。方法所需的這些物件和陣列的參考儲存在 Stack 中。所以。我們為什麼關心?嗯,你看,Stack 比 Heap 小(缺點),但在 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。 : 16位元組
什麼?!記憶體增加了 4 倍!但我們不要就此止步。作為 Java 開發人員,我們通常不會停止使用單一整數。我們真正想要的是使用很多它們。就像按順序一樣。例如,在數組中。或者一個列表。數組和列表一樣儲存在堆中。因此,分配應該花費大約相同的時間。正確的?但是如果我們需要分配更多記憶體怎麼辦?讓我們檢查一下包含 1000 個原始int值的陣列佔了多少空間:
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(對齊/單位填充間隙) 1000 12 4000 12000 40000 400000 3000 30000 300000 30000 30000 30000 300000 300000 300000 300000 3000000 300000 3333333):000 12000/ [I.<elements> N/A 實例大小:4016 位元組空間損失:4 位元組內部+ 0 位元組外部= 總共4 位元組
好吧,考慮到單一 int 需要 4 個位元組,這確實有點道理。包含1000 個整數的ArrayList<Integer>怎麼樣?我們來看一下:
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());
}
結果是 20040 位元組(又是 4 倍!):
java.util.ArrayList@66d3c617d 足跡:計數平均總和描述 1 4016 4016 [Ljava.lang.Object; 1000 16 16000 java.lang.Integer 1 24 24 java.util.ArrayList 1002 20040(總計)
因此,ArrayList<Integer>佔用的記憶體空間是原來的 4 倍。這不好。但是,清單仍然更容易,因為我們可以新增和刪除元素!噢,Java…為什麼你需要把所有東西都裝箱?!但是,我忘記了,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 足跡:計數平均總和描述 1 4016 4016 [I 1 24 24 gnu.trove.list.array.TIntArrayList 2 4040(總計)
所以,最終,我們可以兩全其美!佔用 4 倍空間的整數清單。而且這不涉及Integer實例。僅int。我們 Java 開發人員非常關心記憶體…但我們也關心效能。有一個很棒的微基準測試庫,它的名字很適中,可以讓我們測量程式碼的效能。首先我們來比較計算兩個隨機整數(不論是否裝箱)的和的效能: 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;
}
結果:
主要:test.SampleJavaBenchmark.testBoxedIntegersSum 5693337.344 ±(99.9%) 1198774.178 ops/s [平均值](最小值、平均值、最大值)=(1092314.989、5693337.344835,486,484. CI (99.9%): [4494563.166, 6892111.522] (假設常態分佈) main: test.SampleJavaBenchmark.testPrimitiveIntegersSum 15295010.959 ±(99.9%) 2555447.456 40.959 ±(99.9%) 2555447.456 40.959 ±(99.9%) 2555447.456 447.456 447.456 447.456 447.456 ops/s3% [302507.450447.456 447.456 ops/s50g = 457.456 447.456 447.456 447.456 ops/s. 95010.959, 24283809.447),標準差= 5162130.283 CI (99.9%): [12739563.502, 17850458.415](假設常態分佈)
因此,平均而言,原始整數的分配和求和速度是盒裝整數的兩倍以上。現在,讓我們比較一下集合(或 1000 個整數的陣列)的建立和計算的效能:
@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]
結果:基元數組比裝箱值數組( Integer) 快 4 倍以上;比裝箱值(Integer)的ArrayList快幾乎六倍;速度是TIntArrayList(實際上裝飾原始整數數組)的兩倍。因此,如果您需要一個資料結構來儲存整數值的集合,且其大小不會改變,請使用 int [];如果大小要改變 - 您可能需要將 tove4j 庫與TIntArrayList一起使用。我的文章到此結束,我解釋了使用整數類型的缺點。Integer有一些有趣的靜態方法,我應該在結束之前討論一下。 public static Integer getInteger(String nm, int val)並不像人們想像的那樣,而是檢索系統屬性的Integer值。如果未設定此屬性,則 Val為預設值。public static String toBinaryString(int i)傳回一個帶有數字二進位表示形式的字串。有一些方法可以檢索基於 16 的 ( toHexString ) 和基於 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