Java-Datentypen können bedingt in zwei Blöcke unterteilt werden: Primitive und Referenz (Klassen). In Java gibt es mehrere primitive Datentypen, z. B. Ganzzahlen ( byte , short , int , long ), Gleitkommazahlen ( float , double ), logische Datentypen ( boolean ) und Zeichendatentypen ( char ). Sie wissen wahrscheinlich bereits, dass jeder primitive Datentyp seine eigene Wrapper-Klasse hat. Ein Referenzdatentyp, der seinen primitiven kleinen Bruder in ein Java-Objekt „umhüllt“ oder umwandelt. Integer ist eine Wrapper-Klasse für ihren primitiven Bro namens int. Integer bedeutet im Englischen eine ganze Zahl. Sie können positiv, negativ oder 0 sein. Leider bedeutet Integer in Java keine ganze Zahl. Integer ist in Java eine ganze Zahl, die in 32 Bit passt. Wenn Sie eine größere Zahl wünschen, können Sie gerne Java Long- Zahlen verwenden . Ihnen stehen 64 Bit zur Verfügung. Wenn Sie das Pech haben, eine noch größere Zahl zu benötigen, ist Java mit BigInteger für Sie da .

Arbeiten mit Integer

Als Wrapper-Klasse stellt Integer verschiedene Methoden zum Arbeiten mit int sowie eine Reihe von Methoden zum Konvertieren von int in String und String in int bereit . Die Klasse hat zwei Konstruktoren:
  • public Integer(int i) , wobei i ein zu initialisierender primitiver Wert ist. Dadurch wird ein Integer- Objekt erstellt, das mit dem int- Wert initialisiert wird .

  • public Integer(String s) löst NumberFormatException aus . Hier ist s eine String-Darstellung des int- Werts. Dieser Konstruktor erstellt ein Integer- Objekt, das mit dem durch die Zeichenfolgendarstellung bereitgestellten int- Wert initialisiert wurde .

Erstellung ganzzahliger Objekte

Es gibt verschiedene Optionen zur Erstellung von Integer- Objekten. Einer der am häufigsten verwendeten ist der einfachste. Hier ist ein Beispiel:
Integer myInteger = 5;
Die Initialisierung der Integer- Variablen ähnelt in diesem Fall der Initialisierung der primitiven int- Variablen. Übrigens können Sie eine Integer- Variable mit dem Wert eines int initialisieren . Hier ist ein Beispiel:
int myInt = 5;
Integer myInteger = myInt;
System.out.println(myInteger);
Die Ausgabe hier ist:
5
Tatsächlich können wir hier das automatische Packen beobachten. Außerdem können wir ein Integer- Objekt wie alle anderen Objekte mithilfe eines Konstruktors und des Schlüsselworts new erstellen :
Integer myInteger = new Integer(5);
Mit der Variablen „Integer“ können Sie dasselbe tun wie mit int (addieren, subtrahieren, multiplizieren, dividieren, erhöhen, dekrementieren). Es ist jedoch wichtig zu bedenken, dass Integer ein Referenzdatentyp ist und eine Variable dieses Typs null sein kann. In diesem Fall ist es besser, von solchen Operationen abzusehen.
Integer myInteger1  = null;
Integer myInteger2 = myInteger1 + 5;
Hier erhalten wir eine Ausnahme:
Ausnahme im Thread "main" java.lang.NullPointerException"

Ganzzahlige Klassenkonstanten

Die Integer- Klasse stellt verschiedene Konstanten und Methoden für die Arbeit mit Ganzzahlen bereit. Hier sind sie:
  • GRÖSSE bezeichnet die Anzahl der Bits im zweistelligen Zahlensystem, die vom Typ int belegt sind

  • BYTES ist die Anzahl der Bytes im zweistelligen Zahlensystem, die vom Typ int belegt werden

  • MAX_VALUE ist der maximale Wert, den der int- Typ enthalten kann

  • MIN_VALUE ist der Mindestwert, den der int- Typ enthalten kann

  • TYPE gibt ein Objekt vom Typ Class vom Typ int zurück

Die nützlichsten Methoden der Integer-Klasse

Werfen wir nun einen Blick auf die am häufigsten verwendeten Methoden der Integer- Klasse. Ich vermute, dass die beliebtesten Methoden zum Konvertieren einer Zahl aus einem String oder umgekehrt sind.
  • static int parseInt(String s) Diese Methode konvertiert String in int . Wenn die Konvertierung nicht möglich ist, wird eine NumberFormatException ausgelöst.

  • static int parseInt(String s, int radix) Diese Methode konvertiert auch den s- Parameter in einen int . Der Radix- Parameter gibt an, dass das Zahlensystem s ursprünglich geschrieben wurde.

Neben parseInt gibt es auch eine sehr ähnliche valueOf- Methode in mehreren Variationen. Das Ergebnis von valueOf wird jedoch Integer sein und parseInt wird int sein .
  • static Integer valueOf(int i) gibt eine Ganzzahl zurück, deren Wert i ist ;

  • static Integer valueOf(String s) funktioniert wie parseInt(String s) , aber das Ergebnis ist Integer , nicht int ;

  • static Integer valueOf(String s, int radix) funktioniert genauso wie parseInt(String s, int radix) , aber das Ergebnis ist ein Integer und kein int .

Gibt es ein Problem mit der Integer-Klasse? Oh ja, es gibt ...

Daher gibt es in Java zwei Typen für Ganzzahlen (die in 32 Bit passen): int und Integer . Um die Besonderheiten jedes einzelnen davon zu verstehen, müssen wir Folgendes über das JVM-Speichermodell wissen: Alles, was Sie deklarieren, wird entweder im Stapelspeicher (JVM-Stack spezifisch für jeden Thread) oder im Heap-Speicherplatz gespeichert. Primitive Typen ( int , long , float , boolean , double , char , byte usw.) werden im Stapelspeicher gespeichert. Alle Objekte und Arrays werden im Heap-Bereich gespeichert. Referenzen auf diese Objekte und Arrays, die für die Methoden benötigt werden, werden im Stack gespeichert. Also. Warum kümmert es uns? Nun, Stack ist kleiner als Heap (ein Nachteil), aber es ist viel schneller, Werte im Stack zuzuweisen als im Heap (ein Vorteil). Beginnen wir mit einem primitiven Typ int . Es nimmt genau 32 Bit ein. Das sind 32/8=4 Bytes. Weil es ein primitiver Typ ist. Betrachten wir nun Integer . Es ist ein Objekt mit zusätzlichem Overhead und Ausrichtungen. Ich habe ein Bibliotheksjol verwendet, um seine Größe zu messen:
public static void main(String[] args) {
 	System.out.println(ClassLayout.parseInstance(Integer.valueOf(1)).toPrintable());
}
und es stellte sich heraus, dass es 16 Bytes beanspruchte:
java.lang.Integer-Objektinterna: OFF SZ TYPE BESCHREIBUNG WERT 0 8 (Objekt-Header: Markierung) 0x000000748c90e301 (Hash: 0x748c90e3; Alter: 0) 8 4 (Objekt-Header: Klasse) 0x000492a0 12 4 int Integer.value 1 Instanzgröße: 16 Byte
Was?! Das ist viermal mehr Speicher! Aber lassen Sie uns hier nicht aufhören. Als Java-Entwickler hören wir normalerweise nicht auf, eine einzelne Ganzzahl zu verwenden. Was wir wirklich wollen, ist, viele davon zu nutzen. Wie in einer Sequenz. Zum Beispiel in einem Array. Oder eine Liste. Arrays werden wie Listen im Heap gespeichert. Daher sollte die Zuteilung ungefähr genauso lange dauern. Rechts? Was aber, wenn wir mehr Speicher zuweisen müssen? Schauen wir uns an, wie viel Platz ein Array mit 1000 primitiven int- Werten einnimmt:
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());
}
Und das Ergebnis sind 4016 Bytes:
OFF SZ TYPE BESCHREIBUNG WERT 0 8 (Objekt-Header: Markierung) 0x0000000000000001 (nicht voreingenommen; Alter: 0) 8 4 (Objekt-Header: Klasse) 0x00006c38 12 4 (Array-Länge) 1000 12 4 (Ausrichtung/Auffülllücke) 16 4000 int [I.<Elemente> N/A Instanzgröße: 4016 Bytes Speicherplatzverluste: 4 Bytes intern + 0 Bytes extern = 4 Bytes insgesamt
OK, das macht irgendwie Sinn, wenn man bedenkt, dass ein einzelner Int 4 Bytes benötigt. Was ist mit einer ArrayList<Integer> von 1000 Ganzzahlen ? Werfen wir einen Blick:
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());
}
Und das Ergebnis sind 20040 Bytes (nochmals viermal mehr!):
java.util.ArrayList@66d3c617d Footprint: COUNT AVG SUM BESCHREIBUNG 1 4016 4016 [Ljava.lang.Object; 1000 16 16000 java.lang.Integer 1 24 24 java.util.ArrayList 1002 20040 (gesamt)
ArrayList<Integer> benötigt also viermal mehr Speicherplatz. Das ist nicht gut. Dennoch sind Listen einfacher, da wir Elemente hinzufügen und löschen können! Oh Java ... Warum musst du alles einpacken?! Aber ich vergesse, dass Java großartig ist und seine Größe in der Fülle an Open-Source-Bibliotheken liegt, die wir verwenden können! Trove4j ist einer von ihnen. Es verfügt über TIntArrayList , das intern über int[]- Daten verfügt. Lassen Sie uns seine Größe messen:
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());
}
Und das Ergebnis sind 4040 Bytes (fast das Gleiche wie nur int[] !):
gnu.trove.list.array.TIntArrayList@7440e464d Footprint: COUNT AVG SUM BESCHREIBUNG 1 4016 4016 [I 1 24 24 gnu.trove.list.array.TIntArrayList 2 4040 (gesamt)
Am Ende können wir also das Beste aus beiden Welten haben! Listen mit ganzen Zahlen, die viermal weniger Platz beanspruchen. Dabei handelt es sich nicht um Integer- Instanzen. Nur int s. Uns Java-Entwicklern liegt der Speicher sehr am Herzen ... Aber uns liegt auch die Leistung am Herzen. Es gibt eine wunderbare Mikrobenchmarking-Bibliothek mit dem bescheidenen Namen jmh, mit der wir die Leistung von Code messen können. Vergleichen wir zunächst die Leistung der Berechnung einer Summe zweier zufälliger Ganzzahlen, ob eingerahmt oder nicht: Die Konfiguration für jmh ist wie folgt:
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
Die Benchmarks:
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;
}
Die Ergebnisse:
main: test.SampleJavaBenchmark.testBoxedIntegersSum 5693337,344 ±(99,9 %) 1198774,178 ops/s [Durchschnitt] (min, durchschnittlich, max) = (1092314,989, 5693337,344, 12001683,428), stdev = 242158 3,144 KI (99,9 %): [4494563,166, 6892111,522] (setzt Normalverteilung voraus) main: test.SampleJavaBenchmark.testPrimitiveIntegersSum 15295010,959 ±(99,9 %) 2555447,456 ops/s [Durchschnitt] (min, durchschn., max) = (4560097,059, 15295010,959, 24283809,447), Standardabw = 5162130,283 KI (99,9 %): [12739563.502, 17850458.415] (unter der Annahme einer Normalverteilung)
Daher ist die Zuweisung und Summe primitiver Ganzzahlen im Durchschnitt mehr als doppelt so schnell wie die von geschachtelten Ganzzahlen. Vergleichen wir nun die Leistung der Erstellung und Berechnung der Summe von Sammlungen (oder Arrays mit 1000 ganzen Zahlen):
@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]
Die Ergebnisse: Das Primitiv-Array ist mehr als viermal schneller als das Array mit geschachtelten Werten ( Integer ). fast sechsmal schneller als ArrayList von geschachtelten Werten ( Integer s); und doppelt so schnell wie eine TIntArrayList (die tatsächlich ein Array primitiver Ints dekoriert). Wenn Sie also eine Datenstruktur benötigen, um eine Sammlung ganzzahliger Werte zu speichern, und sich deren Größe nicht ändern soll, verwenden Sie ein int[] ; Wenn sich die Größe ändern soll, möchten Sie möglicherweise die tove4j-Bibliothek mit TIntArrayList verwenden . Und hier kommt das Ende meines Aufsatzes, in dem ich die Nachteile der Verwendung des Integer- Typs erläutere. Es gibt einige interessante statische Methoden von Integer , über die ich sprechen sollte, bevor ich fertig bin. public static Integer getInteger(String nm, int val) macht nicht das, was man denken könnte, sondern ruft einen Integer- Wert einer Systemeigenschaft ab. Val ist der Standardwert, falls diese Eigenschaft nicht festgelegt ist. public static String toBinaryString(int i) gibt einen String mit einer binären Darstellung einer Zahl zurück. Es gibt Methoden zum Abrufen einer 16-basierten ( toHexString ) und 8-basierten ( toOctalString ) Darstellung. Es gibt eine Methode, um einen String in einen int zu analysieren . Auch wenn es sich bei der Zeichenfolge um eine nicht auf 10 Basiswerten basierende Darstellung handelt. Hier sind einige Beispiele: Integer.parseInt("-FF", 16) gibt -255 zurück. Integer.parseInt("+42", 10) gibt 42 zurück . Integer.parseInt("1100110", 2) gibt 102 zurück