Praca z liczbą całkowitą
Jako klasa opakowująca, Integer udostępnia różne metody pracy z int , a także szereg metod konwersji int na String i String na int . Klasa posiada dwa konstruktory:-
public Integer(int i) , gdzie i jest pierwotną wartością do zainicjowania. Ten tworzy obiekt Integer , który jest inicjowany wartością int .
-
public Integer(String s) zgłasza wyjątek NumberFormatException . Tutaj s jest ciągiem reprezentującym wartość int . Ten konstruktor tworzy obiekt Integer , który został zainicjowany wartością int dostarczoną przez reprezentację w postaci ciągu znaków .
Tworzenie obiektów całkowitych
Istnieją różne opcje tworzenia obiektów typu Integer . Jednym z najczęściej używanych jest najłatwiejszy. Oto przykład:Integer myInteger = 5;
Inicjalizacja zmiennej Integer w tym przypadku jest podobna do inicjalizacji pierwotnej zmiennej int . Przy okazji możesz zainicjować zmienną Integer wartością int . Oto przykład:
int myInt = 5;
Integer myInteger = myInt;
System.out.println(myInteger);
Dane wyjściowe to:
Integer myInteger = new Integer(5);
Ze zmienną Integer możesz zrobić to samo, co ze zmienną int (dodawanie, odejmowanie, mnożenie, dzielenie, zwiększanie, zmniejszanie). Należy jednak pamiętać, że Integer jest referencyjnym typem danych i zmienna tego typu może mieć wartość null. W takim przypadku lepiej powstrzymać się od takich operacji.
Integer myInteger1 = null;
Integer myInteger2 = myInteger1 + 5;
Tutaj otrzymamy wyjątek:
Stałe klasy całkowitej
Klasa Integer udostępnia różne stałe i metody pracy z liczbami całkowitymi. Tutaj są:-
ROZMIAR oznacza liczbę bitów w dwucyfrowym systemie liczbowym zajmowaną przez typ int
-
BYTES to liczba bajtów w dwucyfrowym systemie liczbowym zajmowanych przez typ int
-
MAX_VALUE to maksymalna wartość, jaką może przechowywać typ int
-
MIN_VALUE to minimalna wartość, jaką może przechowywać typ int
-
TYPE zwraca obiekt typu Class z typu int
Najbardziej przydatne metody klasy całkowitej
Przyjrzyjmy się teraz najczęściej używanym metodom klasy Integer . Przypuszczam, że najpopularniejsze z nich to metody konwersji liczby z String i odwrotnie.-
static int parseInt(String s) ta metoda konwertuje String na int . Jeśli konwersja nie jest możliwa, zostanie zgłoszony wyjątek NumberFormatException .
-
static int parseInt(String s, int radix) ta metoda konwertuje również parametr s na int . Parametr radix wskazuje, w jakim systemie liczbowym s został pierwotnie zapisany.
-
statyczna liczba całkowita wartośćOf(int i) zwraca liczbę całkowitą , której wartość wynosi i ;
-
statyczna liczba całkowita valueOf(String s) działa jak parseInt(String s) , ale wynikiem będzie Integer , a nie int ;
-
static Integer valueOf(String s, int radix) działa tak samo jak parseInt(String s, int radix) , ale wynikiem jest liczba całkowita , a nie int .
Czy jest jakiś problem z klasą Integer? O tak, jest…
Zatem w Javie istnieją dwa typy liczb całkowitych (które mieszczą się w 32 bitach): int i Integer . Aby zrozumieć specyfikę każdego z nich, musimy wiedzieć co następuje o modelu pamięci JVM: wszystko, co zadeklarujesz, jest przechowywane albo w pamięci stosu (stos JVM specyficzny dla każdego wątku), albo w przestrzeni sterty. Typy pierwotne ( int , long , float , boolean , double , char , byte itp.) są przechowywane w pamięci stosu. Wszystkie obiekty i tablice są przechowywane w przestrzeni sterty. Odniesienia do tych obiektów i tablic potrzebnych do metod są przechowywane w Stack. Więc. Dlaczego nas to obchodzi? Cóż, widzisz, stos jest mniejszy niż sterta (wada), ale przydzielanie wartości w stosie jest znacznie szybsze niż w stercie (pro). Zacznijmy od typu pierwotnego int . Zajmuje dokładnie 32 bity. To 32/8 = 4 bajty. Ponieważ jest to typ prymitywny. Rozważmy teraz liczbę całkowitą . Jest to obiekt z dodatkowym narzutem i wyrównaniem. Użyłem biblioteki jol do zmierzenia jej rozmiaru:public static void main(String[] args) {
System.out.println(ClassLayout.parseInstance(Integer.valueOf(1)).toPrintable());
}
i okazało się, że zajmuje 16 bajtów:
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());
}
Wynik to 4016 bajtów:
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());
}
Wynik to 20040 bajtów (znowu 4 razy więcej!):
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());
}
Rezultatem jest 4040 bajtów (prawie tyle samo, co 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
Punkty odniesienia:
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;
}
Wyniki:
@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]
Wyniki: tablica prymitywów jest ponad 4 razy szybsza niż tablica wartości w ramkach ( Integer s); prawie sześć razy szybciej niż ArrayList wartości pudełkowych ( Integer s); i dwa razy szybciej niż TIntArrayList (która faktycznie ozdabia tablicę prymitywnych wartości typu int). Dlatego jeśli potrzebujesz struktury danych do przechowywania kolekcji wartości całkowitych, a jej rozmiar się nie zmieni, użyj int [] ; jeśli rozmiar ma się zmienić — możesz użyć biblioteki tove4j z TIntArrayList . I tu kończy się mój esej, w którym wyjaśniam wady używania typu Integer . Istnieje kilka interesujących metod statycznych Integer , o których powinienem porozmawiać, zanim skończę. public static Integer getInteger(String nm, int val) nie robi tego, co mogłoby się wydawać, ale pobiera wartość Integer właściwości systemowej. Val jest wartością domyślną w przypadku, gdy ta właściwość nie jest ustawiona. public static String toBinaryString(int i) zwraca ciąg z binarną reprezentacją liczby. Istnieją metody pobierania reprezentacji opartych na 16 ( toHexString ) i opartych na 8 ( toOctalString ). Istnieje metoda parsowania ciągu znaków na int . Nawet jeśli ciąg nie jest reprezentacją opartą na podstawie innej niż 10. Oto kilka przykładów: Integer.parseInt("-FF", 16) zwraca -255 Integer.parseInt("+42", 10) zwraca 42 Integer.parseInt("1100110", 2) zwraca 102