Ricerca…


introduzione

Gli 8 tipi di dati primitivi byte , short , int , long , char , boolean , float e double sono i tipi che memorizzano la maggior parte dei dati numerici grezzi nei programmi Java.

Sintassi

  • int aInt = 8; // La parte di definizione (numero) di questa dichiarazione int è detta letterale.

  • int hexInt = 0x1a; // = 26; È possibile definire valori letterali con valori esadecimali preceduti da 0x .

  • int binInt = 0b11010; // = 26; È inoltre possibile definire valori letterali binari; prefisso con 0b .

  • long good Long = 10000000000L; // Per impostazione predefinita, i valori letterali interi sono di tipo int. Aggiungendo la L alla fine del letterale stai dicendo al compilatore che il letterale è lungo. Senza questo il compilatore genererebbe un errore "Numero intero troppo grande".

  • double aDouble = 3,14; // I letterali a virgola mobile sono di tipo double per impostazione predefinita.

  • float aFloat = 3.14F; // Per impostazione predefinita questo letterale sarebbe stato un double (e causato un errore "Tipi incompatibili"), ma aggiungendo una F diciamo al compilatore che è un float.

Osservazioni

Java ha 8 tipi di dati primitivi , vale a dire boolean , byte , short , char , int , long , float e double . (Tutti gli altri tipi sono tipi di riferimento, inclusi tutti i tipi di array e tipi / classi di oggetti incorporati che hanno un significato speciale nel linguaggio Java, ad esempio String , Class e Throwable e le relative sottoclassi.)

Il risultato di tutte le operazioni (addizione, sottrazione, moltiplicazione, ecc.) Su un tipo primitivo è almeno un int , quindi aggiungendo un short a un short produce un int , come aggiungere un byte a un byte o un char a un char . Se vuoi assegnare il risultato di quel ritorno ad un valore dello stesso tipo, devi lanciarlo. per esempio

byte a = 1;
byte b = 2;
byte c = (byte) (a + b);

La mancata esecuzione dell'operazione comporterà un errore di compilazione.

Ciò è dovuto alla seguente parte della Java Language Spec, §2.11.1 :

Un compilatore codifica carichi di valori letterali di tipi byte e short utilizzando le istruzioni Java Virtual Machine che firmano-estendono tali valori ai valori di tipo int al momento della compilazione o in fase di esecuzione. Carichi di valori letterali di tipi boolean e char sono codificati usando istruzioni che estendono a zero il valore letterale a un valore di tipo int al momento della compilazione o in fase di esecuzione. [..]. Quindi, la maggior parte delle operazioni sui valori di tipi reali boolean , byte , char e short vengono eseguite correttamente mediante istruzioni che operano su valori di tipo computazionale int .

La ragione di ciò è specificata anche in quella sezione:

Data la dimensione dell'opcode a byte singolo di Java Virtual Machine, i tipi di codifica in opcode mettono pressione sul design del set di istruzioni. Se ogni istruzione digitata supportava tutti i tipi di dati di runtime della Java Virtual Machine, ci sarebbero più istruzioni di quante potrebbero essere rappresentate in un byte . [...] È possibile utilizzare istruzioni separate per convertire tra tipi di dati non supportati e supportati, se necessario.

Il primitivo int

Un tipo di dati primitivo come int detiene i valori direttamente nella variabile che lo utilizza, nel frattempo una variabile che è stata dichiarata utilizzando Integer contiene un riferimento al valore.

In base all'API java : "La classe Integer racchiude un valore del tipo primitivo int in un oggetto. Un oggetto di tipo Integer contiene un singolo campo il cui tipo è int."

Per impostazione predefinita, int è un numero intero con int a 32 bit. Può memorizzare un valore minimo di -2 31 e un valore massimo di 2 31 - 1.

int example = -42;
int myInt = 284;
int anotherInt = 73;

int addedInts = myInt + anotherInt; // 284 + 73 = 357
int subtractedInts = myInt - anotherInt; // 284 - 73 = 211

Se è necessario memorizzare un numero al di fuori di questo intervallo, dovrebbe essere usato a long . Il superamento dell'intervallo di valori di int causa un overflow di un intero, causando il valore che supera l'intervallo da aggiungere al sito opposto dell'intervallo (positivo diventa negativo e viceversa). Il valore è ((value - MIN_VALUE) % RANGE) + MIN_VALUE o ((value + 2147483648) % 4294967296) - 2147483648

int demo = 2147483647; //maximum positive integer
System.out.println(demo); //prints 2147483647
demo = demo + 1; //leads to an integer overflow
System.out.println(demo); // prints -2147483648

I valori massimi e minimi di int possono essere trovati a:

int high = Integer.MAX_VALUE;    // high == 2147483647
int low = Integer.MIN_VALUE;     // low == -2147483648

Il valore predefinito di un int è 0

int defaultInt;    // defaultInt == 0

Il breve primitivo

Un short è un intero con segno a 16 bit. Ha un valore minimo di -2 15 (-32.768) e un valore massimo di 2 15 -1 (32.767)

short example = -48;
short myShort = 987;
short anotherShort = 17;

short addedShorts = (short) (myShort + anotherShort); // 1,004
short subtractedShorts = (short) (myShort - anotherShort); // 970

I valori massimi e minimi del short possono essere trovati a:

short high = Short.MAX_VALUE;        // high == 32767
short low = Short.MIN_VALUE;         // low == -32768

Il valore predefinito di un short è 0

short defaultShort;    // defaultShort == 0

Il lungo primitivo

Per impostazione predefinita, long è un intero con segno a 64 bit (in Java 8, può essere firmato o non firmato). Firmato, può memorizzare un valore minimo di -2 63 e un valore massimo di 2 63 - 1, e senza segno può memorizzare un valore minimo di 0 e un valore massimo di 2 64 - 1

long example = -42;
long myLong = 284;
long anotherLong = 73;

//an "L" must be appended to the end of the number, because by default,
//numbers are assumed to be the int type. Appending an "L" makes it a long
//as 549755813888 (2 ^ 39) is larger than the maximum value of an int (2^31 - 1),
//"L" must be appended 
long bigNumber = 549755813888L;

long addedLongs = myLong + anotherLong; // 284 + 73 = 357
long subtractedLongs = myLong - anotherLong; // 284 - 73 = 211

I valori massimo e minimo di long possono essere trovati a:

long high = Long.MAX_VALUE;    // high == 9223372036854775807L
long low = Long.MIN_VALUE;     // low == -9223372036854775808L

Il valore predefinito di long è 0L

long defaultLong;    // defaultLong == 0L

Nota: la lettera "L" aggiunta alla fine del letterale long fa distinzione tra maiuscole e minuscole, tuttavia è buona norma utilizzare il capitale in quanto è più semplice distinguere dal primo:

2L == 2l;            // true

Avviso: cache Java istanze di oggetti interi nell'intervallo da -128 a 127. Il ragionamento è spiegato qui: https://blogs.oracle.com/darcy/entry/boxing_and_caches_integer_valueof

I seguenti risultati possono essere trovati:

Long val1 = 127L;
Long val2 = 127L;

System.out.println(val1 == val2); // true

Long val3 = 128L;
Long val4 = 128L;

System.out.println(val3 == val4); // false

Per confrontare correttamente 2 valori Long Object, utilizzare il codice seguente (da Java 1.7 in poi):

Long val3 = 128L;
Long val4 = 128L;

System.out.println(Objects.equal(val3, val4)); // true

Confrontare un primitivo lungo ad un oggetto lungo non darà come risultato un falso negativo come confrontare 2 oggetti con ==.

Il primitivo booleano

Un boolean può memorizzare uno dei due valori, true o false

boolean foo = true;
System.out.println("foo = " + foo);                // foo = true

boolean bar = false;
System.out.println("bar = " + bar);                // bar = false

boolean notFoo = !foo;
System.out.println("notFoo = " + notFoo);          // notFoo = false

boolean fooAndBar = foo && bar;
System.out.println("fooAndBar = " + fooAndBar);    // fooAndBar = false

boolean fooOrBar = foo || bar;
System.out.println("fooOrBar = " + fooOrBar);      // fooOrBar = true

boolean fooXorBar = foo ^ bar;
System.out.println("fooXorBar = " + fooXorBar);    // fooXorBar = true

Il valore predefinito di un boolean è falso

boolean defaultBoolean;    // defaultBoolean == false

Il byte primitivo

Un byte è un intero con byte a 8 bit. Può memorizzare un valore minimo di -2 7 (-128) e un valore massimo di 2 7 - 1 (127)

byte example = -36;
byte myByte = 96;
byte anotherByte = 7;

byte addedBytes = (byte) (myByte + anotherByte); // 103
byte subtractedBytes = (byte) (myBytes - anotherByte); // 89

I valori massimi e minimi di byte possono essere trovati su:

byte high = Byte.MAX_VALUE;        // high == 127
byte low = Byte.MIN_VALUE;         // low == -128

Il valore predefinito di un byte è 0

byte defaultByte;    // defaultByte == 0

Il galleggiante primitivo

Un float è un numero a virgola mobile IEEE 754 a 32 bit a precisione singola. Per impostazione predefinita, i decimali vengono interpretati come doppi. Per creare un float , è sufficiente aggiungere un f al letterale decimale.

double doubleExample = 0.5;      // without 'f' after digits = double
float floatExample = 0.5f;       // with 'f' after digits    = float

float myFloat = 92.7f;           // this is a float...
float positiveFloat = 89.3f;     // it can be positive,
float negativeFloat = -89.3f;    // or negative
float integerFloat = 43.0f;      // it can be a whole number (not an int)
float underZeroFloat = 0.0549f;  // it can be a fractional value less than 0

I float gestiscono le cinque operazioni aritmetiche comuni: addizione, sottrazione, moltiplicazione, divisione e modulo.

Nota: quanto segue può variare leggermente a causa di errori in virgola mobile. Alcuni risultati sono stati arrotondati per chiarezza e leggibilità (il risultato stampato dell'esempio di addizione era in realtà 34.600002).

// addition
float result = 37.2f + -2.6f;  // result: 34.6

// subtraction
float result = 45.1f - 10.3f;    // result: 34.8

// multiplication
float result = 26.3f * 1.7f;   // result: 44.71

// division
float result = 37.1f / 4.8f;   // result: 7.729166

// modulus
float result = 37.1f % 4.8f;   // result: 3.4999971

A causa del modo in cui i numeri in virgola mobile vengono memorizzati (ad esempio in formato binario), molti numeri non hanno una rappresentazione esatta.

float notExact = 3.1415926f;
System.out.println(notExact); // 3.1415925

Sebbene l'uso di float bene per la maggior parte delle applicazioni, non è necessario utilizzare né floatdouble per memorizzare rappresentazioni esatte di numeri decimali (come importi monetari) o numeri in cui è richiesta una maggiore precisione. Invece, dovrebbe essere usata la classe BigDecimal .

Il valore predefinito di un float è 0.0f .

float defaultFloat;    // defaultFloat == 0.0f

Un float è preciso a circa un errore di 1 su 10 milioni.

Nota: Float.POSITIVE_INFINITY , Float.NEGATIVE_INFINITY , Float.NaN sono float valori. NaN sta per risultati di operazioni che non possono essere determinate, come la divisione di 2 valori infiniti. Inoltre 0f e -0f sono diversi, ma == si -0f vero:

float f1 = 0f;
float f2 = -0f;
System.out.println(f1 == f2); // true
System.out.println(1f / f1); // Infinity
System.out.println(1f / f2); // -Infinity
System.out.println(Float.POSITIVE_INFINITY / Float.POSITIVE_INFINITY); // NaN

Il doppio primitivo

Un double è un numero a virgola mobile IEEE 754 a 64 bit a doppia precisione.

double example = -7162.37;
double myDouble = 974.21;
double anotherDouble = 658.7;

double addedDoubles = myDouble + anotherDouble; // 315.51
double subtractedDoubles = myDouble - anotherDouble; // 1632.91

double scientificNotationDouble = 1.2e-3;    // 0.0012

A causa del modo in cui vengono memorizzati i numeri in virgola mobile, molti numeri non hanno una rappresentazione esatta.

double notExact = 1.32 - 0.42; // result should be 0.9
System.out.println(notExact); // 0.9000000000000001

Mentre l'uso del double va bene per la maggior parte delle applicazioni, non è necessario utilizzare né floatdouble per memorizzare numeri precisi come la valuta. Invece, dovrebbe essere usata la classe BigDecimal

Il valore predefinito di un double è 0.0d

public double defaultDouble;    // defaultDouble == 0.0

Nota: Double.POSITIVE_INFINITY , Double.NEGATIVE_INFINITY , Double.NaN sono valori double . NaN sta per risultati di operazioni che non possono essere determinate, come la divisione di 2 valori infiniti. Inoltre 0d e -0d sono diversi, ma == si -0d vero:

double d1 = 0d;
double d2 = -0d;
System.out.println(d1 == d2); // true
System.out.println(1d / d1); // Infinity
System.out.println(1d / d2); // -Infinity
System.out.println(Double.POSITIVE_INFINITY / Double.POSITIVE_INFINITY); // NaN

Il primitivo char

Un char può memorizzare un singolo carattere Unicode a 16 bit. Un letterale di carattere è racchiuso tra virgolette singole

char myChar = 'u';
char myChar2 = '5';
char myChar3 = 65; // myChar3 == 'A'

Ha un valore minimo di \u0000 (0 nella rappresentazione decimale, chiamata anche carattere null ) e un valore massimo di \uffff (65.535).

Il valore predefinito di un char è \u0000 .

char defaultChar;    // defaultChar == \u0000

Per definire un char di ' valore, è necessario utilizzare una sequenza di escape (carattere preceduto da una barra rovesciata):

char singleQuote = '\'';

Ci sono anche altre sequenze di escape:

char tab = '\t';
char backspace = '\b';
char newline = '\n';
char carriageReturn = '\r';
char formfeed = '\f';
char singleQuote = '\'';
char doubleQuote = '\"'; // escaping redundant here; '"' would be the same; however still allowed
char backslash = '\\';
char unicodeChar = '\uXXXX' // XXXX represents the Unicode-value of the character you want to display

È possibile dichiarare un char di qualsiasi carattere Unicode.

char heart = '\u2764';
System.out.println(Character.toString(heart)); // Prints a line containing "❤".

È anche possibile aggiungere a un char . ad esempio per scorrere tutte le lettere minuscole, è possibile fare quanto segue:

for (int i = 0; i <= 26; i++) {
    char letter = (char) ('a' + i);
    System.out.println(letter);
}

Rappresentazione del valore negativo

Java e molti altri linguaggi memorizzano numeri interi negativi in ​​una rappresentazione chiamata notazione complemento a 2 .

Per una rappresentazione binaria univoca di un tipo di dati utilizzando n bit, i valori sono codificati in questo modo:

I bit meno significativi di n-1 memorizzano un numero integrale positivo x in rappresentazione integrale. Il valore più significativo memorizza un valore di bit vith s . Il valore ripreso da quei bit è

x - s * 2 n-1

cioè se il bit più significativo è 1, allora un valore che è solo di 1 più grande del numero che potresti rappresentare con gli altri bit ( 2 n-2 + 2 n-3 + ... + 2 1 + 2 0 = 2 n-1 - 1 ) viene sottratto consentendo una rappresentazione binaria univoca per ogni valore da - 2 n-1 (s = 1; x = 0) a 2 n-1 - 1 (s = 0; x = 2 n-1 - 1).

Questo ha anche il bell'effetto collaterale, che è possibile aggiungere le rappresentazioni binarie come se fossero numeri binari positivi:

v1 = x1 - s1 * 2n-1
v2 = x2 - s2 * 2n-1
s1 s2 x1 + x2 overflow risultato aggiuntivo
0 0 No x1 + x2 = v1 + v2
0 0 troppo grande per essere rappresentata con il tipo di dati (overflow)
0 1 No
x1 + x2 - 2n-1 = x1 + x2 - s2 * 2n-1
= v1 + v2
0 1
(x1 + x2) mod 2n-1 = x1 + x2 - 2n-1
= v1 + v2
1 0 * vedi sopra (scambia i contatti)
1 1 No troppo piccolo per essere rappresentato con il tipo di dati (x1 + x2 - 2 n <-2 n-1 ; underflow)
1 1
(x1 + x2) mod 2n-1 - 2n-1 = (x1 + x2 - 2n-1) - 2n-1
= (x1 - s1 * 2n-1) + (x2 - s2 * 2n-1)
= v1 + v2

Si noti che questo fatto rende facile trovare la rappresentazione binaria dell'inverso additivo (cioè il valore negativo):

Osservare che aggiungendo il complemento bit per bit al numero risulta che tutti i bit siano 1. Ora aggiungi 1 per rendere il valore overflow e ottieni l'elemento neutro 0 (tutti i bit 0).

Quindi il valore negativo di un numero i può essere calcolata utilizzando (ignorando possibile promozione a int qui)

(~i) + 1

Esempio: prendendo il valore negativo di 0 ( byte ):

Il risultato della negazione di 0 è 11111111 . L'aggiunta di 1 fornisce un valore di 100000000 (9 bit). Poiché un byte può solo memorizzare 8 bit, il valore più a sinistra viene troncato e il risultato è 00000000

Originale Processi Risultato
0 (00000000) Negare -0 (11111111)
11111111 Aggiungi 1 al binario 100000000
100000000 Tronca a 8 bit 00000000 (-0 è uguale a 0)

Consumo di memoria dei primitivi rispetto ai primitivi inscatolati

Primitivo Tipo in scatola Dimensione della memoria di primitivo / in scatola
booleano booleano 1 byte / 16 byte
byte Byte 1 byte / 16 byte
corto Corto 2 byte / 16 byte
carbonizzare carbonizzare 2 byte / 16 byte
int Numero intero 4 byte / 16 byte
lungo Lungo 8 byte / 16 byte
galleggiante Galleggiante 4 byte / 16 byte
Doppio Doppio 8 byte / 16 byte

Gli oggetti in scatola richiedono sempre 8 byte per tipo e gestione della memoria, e poiché la dimensione degli oggetti è sempre un multiplo di 8, tutti i tipi di box richiedono 16 byte totali . Inoltre , ogni utilizzo di un oggetto scatolato comporta la memorizzazione di un riferimento che tiene conto di altri 4 o 8 byte, a seconda delle opzioni JVM e JVM.

Nelle operazioni a uso intensivo di dati, il consumo di memoria può avere un notevole impatto sulle prestazioni. Il consumo di memoria aumenta ulteriormente quando si utilizzano gli array: un array float[5] richiede solo 32 byte; mentre un Float[5] memorizza 5 valori distinti non nulli richiederà un totale di 112 byte (su 64 bit senza puntatori compressi, questo aumenta a 152 byte).

Cache di valore in scatola

Gli overheads spaziali dei tipi di box possono essere mitigati in misura maggiore dalle cache del valore in box. Alcuni tipi di box implementano una cache di istanze. Ad esempio, per impostazione predefinita, la classe Integer memorizzerà nella cache le istanze per rappresentare numeri nell'intervallo da -128 a +127 . Ciò, tuttavia, non riduce il costo aggiuntivo derivante dall'indirizzamento aggiuntivo della memoria.

Se si crea un'istanza di un tipo in box mediante autoboxing o chiamando il valueOf(primitive) statico valueOf(primitive) , il sistema runtime tenterà di utilizzare un valore memorizzato nella cache. Se l'applicazione utilizza molti valori nell'intervallo che viene memorizzato nella cache, questo può ridurre in modo sostanziale la penalità della memoria dell'utilizzo di tipi di box. Certamente, se crei istanze di valore in box "a mano", è meglio usare valueOf piuttosto che new . (La new operazione crea sempre una nuova istanza.) Se, tuttavia, la maggior parte dei valori non si trova nell'intervallo memorizzato nella cache, può essere più veloce chiamare la new e salvare la ricerca della cache.

Conversione di primitivi

In Java, possiamo convertire tra valori interi e valori a virgola mobile. Inoltre, poiché ogni carattere corrisponde a un numero nella codifica Unicode, i tipi di char possono essere convertiti in e da tipi interi e in virgola mobile. boolean è l'unico tipo di dati primitivo che non può essere convertito in o da qualsiasi altro tipo di dati primitivo.

Esistono due tipi di conversioni: conversione allargata e conversione restringimento .

Una conversione allargata è quando un valore di un tipo di dati viene convertito in un valore di un altro tipo di dati che occupa più bit rispetto al primo. In questo caso non vi è alcun problema di perdita di dati.

Corrispondentemente, una conversione restringimento è quando un valore di un tipo di dati viene convertito in un valore di un altro tipo di dati che occupa meno bit del primo. La perdita di dati può verificarsi in questo caso.

Java esegue automaticamente l' ampliamento delle conversioni . Ma se si desidera eseguire una conversione di restringimento (se si è certi che non si verificherà alcuna perdita di dati), è possibile forzare Java ad eseguire la conversione utilizzando un costrutto linguistico noto come cast .

Conversione allargata:

int a = 1;    
double d = a;    // valid conversion to double, no cast needed (widening)

Riduzione della conversione:

double d = 18.96
int b = d;       // invalid conversion to int, will throw a compile-time error
int b = (int) d; // valid conversion to int, but result is truncated (gets rounded down)
                 // This is type-casting
                 // Now, b = 18

Cheatsheet Tipi primitivi

Tabella che mostra le dimensioni e l'intervallo di valori di tutti i tipi primitivi:

tipo di dati rappresentazione numerica intervallo di valori valore predefinito
booleano n / A falso e vero falso
byte Firmato a 8 bit -2 7 a 2 7 - 1 0
Da -128 a +127
corto Firmato a 16 bit -2 15 a 2 15 - 1 0
Da -32.768 a +32.767
int Firmato a 32 bit -2 31 a 2 31 - 1 0
-2,147,483,648 a +2,147,483,647
lungo Firmato a 64 bit -2 63 a 2 63 - 1 0L
-9.223.372.036.854.775.808 a 9.223.372.036.854.775.807
galleggiante 32 virgola mobile 1.401298464e-45 a 3.402823466e + 38 (positivo o negativo) 0.0f
Doppio Virgola mobile a 64 bit 4.94065645841246544e-324d a 1.79769313486231570e + 308d (positivo o negativo) 0.0D
carbonizzare 16 bit senza segno Da 0 a 2 16 - 1 0
Da 0 a 65.535

Gli appunti:

  1. La specifica del linguaggio Java richiede che i tipi integrali firmati (da byte a long ) utilizzino la rappresentazione binaria del complemento a due e che i tipi a virgola mobile utilizzino rappresentazioni in virgola mobile binarie IEE 754 standard.
  2. Java 8 e versioni successive forniscono metodi per eseguire operazioni aritmetiche non firmate su int e long . Sebbene questi metodi consentano a un programma di trattare i valori dei rispettivi tipi come non firmati, i tipi restano tipi firmati.
  3. Il più piccolo punto fluttuante mostrato sopra è subnormale ; cioè hanno meno precisione di un valore normale . I numeri normali più piccoli sono 1.175494351e-38 e 2.2250738585072014e-308
  4. Un char rappresenta convenzionalmente un'unità di codice Unicode / UTF-16.
  5. Sebbene un boolean contenga solo un bit di informazione, la sua dimensione in memoria varia a seconda dell'implementazione di Java Virtual Machine (si veda il tipo booleano ).


Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow