Java Language
operatori
Ricerca…
introduzione
Gli operatori nel linguaggio di programmazione Java sono simboli speciali che eseguono operazioni specifiche su uno, due o tre operandi e quindi restituiscono un risultato.
Osservazioni
Un operatore è un simbolo (o simboli) che indica a un programma Java di eseguire un'operazione su uno, due o tre operandi . Un operatore e i suoi operandi formano un'espressione (vedere l'argomento Espressioni). Gli operandi di un operatore sono essi stessi espressioni.
Questo argomento descrive i 40 operatori distinti definiti da Java. L'argomento delle espressioni separate spiega:
- in che modo operatori, operandi e altre cose sono combinati in espressioni,
- come vengono valutate le espressioni e
- come funzionano le espressioni di battitura, le conversioni e le espressioni.
The String Concatenation Operator (+)
Il simbolo +
può significare tre operatori distinti in Java:
- Se non c'è un operando prima del
+
, allora è l'operatore unario Plus. - Se ci sono due operandi e sono entrambi numerici. quindi è l'operatore di aggiunta binaria.
- Se ci sono due operandi e almeno uno di essi è una
String
, allora è l'operatore di concatenazione binaria.
Nel caso semplice, l'operatore Concatenazione unisce due stringhe per dare una terza stringa. Per esempio:
String s1 = "a String";
String s2 = "This is " + s1; // s2 contains "This is a String"
Quando uno dei due operandi non è una stringa, viene convertito in una String
come segue:
Un operando il cui tipo è di tipo primitivo viene convertito come se chiamasse
toString()
sul valore box.Un operando il cui tipo è un tipo di riferimento viene convertito chiamando il metodo
toString()
dell'operando. Se l'operando ènull
o se il metodotoString()
restituiscenull
, viene utilizzata la stringa letterale"null"
.
Per esempio:
int one = 1;
String s3 = "One is " + one; // s3 contains "One is 1"
String s4 = null + " is null"; // s4 contains "null is null"
String s5 = "{1} is " + new int[]{1}; // s5 contains something like
// "{} is [I@xxxxxxxx"
La spiegazione per l'esempio s5
è che il metodo toString()
sui tipi di array è ereditato da java.lang.Object
e il comportamento è quello di produrre una stringa che comprende il nome del tipo e l'hashcode dell'identità dell'oggetto.
L'operatore Concatenazione viene specificato per creare un nuovo oggetto String
, tranne nel caso in cui l'espressione sia un'espressione costante. In quest'ultimo caso, l'espressione viene valutata al tipo di compilazione e il suo valore di runtime è equivalente a un valore letterale stringa. Ciò significa che non c'è nessun sovraccarico di runtime nel dividere un lungo letterale come questo:
String typing = "The quick brown fox " +
"jumped over the " +
"lazy dog"; // constant expression
Ottimizzazione ed efficienza
Come notato sopra, con l'eccezione delle espressioni costanti, ogni espressione di concatenazione di stringhe crea un nuovo oggetto String
. Considera questo codice:
public String stars(int count) {
String res = "";
for (int i = 0; i < count; i++) {
res = res + "*";
}
return res;
}
Nel metodo sopra, ogni iterazione del ciclo creerà una nuova String
che è un carattere più lungo rispetto alla precedente iterazione. Ogni concatenazione copia tutti i caratteri nelle stringhe degli operandi per formare la nuova String
. Quindi, le stars(N)
:
- crea
N
nuovi oggettiString
, e butta via tutto tranne l'ultimo, - copia
N * (N + 1) / 2
caratteri e - genera
O(N^2)
byte di spazzatura.
Questo è molto costoso per il grande N
In effetti, qualsiasi codice che concatena stringhe in un ciclo è suscettibile di avere questo problema. Un modo migliore per scrivere questo sarebbe il seguente:
public String stars(int count) {
// Create a string builder with capacity 'count'
StringBuilder sb = new StringBuilder(count);
for (int i = 0; i < count; i++) {
sb.append("*");
}
return sb.toString();
}
Idealmente, si dovrebbe impostare la capacità della StringBuilder
, ma se questo non è pratico, la classe crescerà automaticamente la matrice supporto che il costruttore utilizza per tenere caratteri. (Nota: l'implementazione espande l'array di supporto in modo esponenziale. Questa strategia mantiene quella quantità di copia del personaggio su un O(N)
piuttosto che su O(N^2)
.)
Alcune persone applicano questo modello a tutte le concatenazioni di stringhe. Tuttavia, questo non è necessario perché il JLS consente a un compilatore Java di ottimizzare le concatenazioni di stringhe all'interno di una singola espressione. Per esempio:
String s1 = ...;
String s2 = ...;
String test = "Hello " + s1 + ". Welcome to " + s2 + "\n";
sarà tipicamente ottimizzato dal compilatore bytecode per qualcosa di simile;
StringBuilder tmp = new StringBuilder();
tmp.append("Hello ")
tmp.append(s1 == null ? "null" + s1);
tmp.append("Welcome to ");
tmp.append(s2 == null ? "null" + s2);
tmp.append("\n");
String test = tmp.toString();
(Il compilatore JIT può ottimizzarlo ulteriormente se può dedurre che s1
o s2
non può essere null
.) Ma si noti che questa ottimizzazione è consentita solo all'interno di una singola espressione.
In breve, se sei preoccupato dell'efficienza delle concatenazioni di stringhe:
- Ottimizza a mano se esegui una concatenazione ripetuta in un ciclo (o simile).
- Non ottimizzare a mano una singola espressione di concatenazione.
Gli operatori aritmetici (+, -, *, /,%)
Il linguaggio Java fornisce 7 operatori che eseguono l'aritmetica su valori interi e in virgola mobile.
- Ci sono due operatori
+
:- L'operatore di aggiunta binaria aggiunge un numero a un altro. (Esiste anche un operatore binario
+
che esegue la concatenazione di stringhe, come descritto in un esempio separato). - L'operatore unario plus non fa nulla oltre all'attivazione della promozione numerica (vedi sotto)
- L'operatore di aggiunta binaria aggiunge un numero a un altro. (Esiste anche un operatore binario
- Ci sono due
-
operatori:- L'operatore di sottrazione binaria sottrae un numero da un altro.
- L'operatore unario meno equivale a sottrarre il suo operando da zero.
- L'operatore di moltiplicazione binario (*) moltiplica un numero per un altro.
- L'operatore di divisione binaria (/) divide un numero per un altro.
- L'operatore del resto 1 binario (%) calcola il resto quando un numero viene diviso per un altro.
1. Questo è spesso erroneamente definito come l'operatore "modulo". "Remainder" è il termine utilizzato da JLS. "Modulo" e "resto" non sono la stessa cosa.
Operand e tipi di risultato e promozione numerica
Gli operatori richiedono operandi numerici e producono risultati numerici. I tipi di operando possono essere qualsiasi tipo di carattere numerico primitivo (es. byte
, short
, char
, int
, long
, float
o double
) o qualsiasi tipo di wrapper numerico definito in java.lang
; es. ( Byte
, Character
, Short
, Integer
, Long
, Float
o Double
.
Il tipo di risultato è determinato in base ai tipi dell'operando o degli operandi, come segue:
- Se uno degli operandi è
double
oDouble
, il tipo di risultato èdouble
. - Altrimenti, se uno degli operandi è
float
oFloat
, il tipo di risultato èfloat
. - Altrimenti, se uno degli operandi è
long
oLong
, il tipo di risultato èlong
. - Altrimenti, il tipo di risultato è
int
. Questo coprebyte
,short
echar
operandi così come `int.
Il tipo di risultato dell'operazione determina come viene eseguita l'operazione aritmetica e come vengono gestiti gli operandi
- Se il tipo di risultato è
double
, gli operandi vengono promossi adouble
e l'operazione viene eseguita utilizzando l'aritmetica in virgola mobile IEE 754 a 64 bit (binario a precisione doppia). - Se il tipo di risultato è
float
, gli operandi vengono promossi infloat
e l'operazione viene eseguita utilizzando l'aritmetica in virgola mobile IEE 754 a 32 bit (binario a precisione singola). - Se il tipo di risultato è
long
, gli operandi vengono promossi along
e l'operazione viene eseguita utilizzando l'aritmetica di numeri interi binari a due complementi con segno a 64 bit. - Se il tipo di risultato è
int
, gli operandi vengono promossi aint
e l'operazione viene eseguita utilizzando l'aritmetica di numeri interi binari a due complementi con segno a 32 bit.
La promozione viene eseguita in due fasi:
- Se il tipo di operando è un tipo di wrapper, il valore dell'operando è non inserito in un valore del tipo primitivo corrispondente.
- Se necessario, il tipo primitivo viene promosso al tipo richiesto:
- La promozione di interi per
int
olong
è senza perdite. - La promozione del
float
dadouble
è senza perdite. - La promozione di un intero con un valore in virgola mobile può portare a una perdita di precisione. La conversione viene eseguita utilizzando la semantica IEE 768 "round-to-nearest".
- La promozione di interi per
Il significato della divisione
L'operatore / divide l'operando di sinistra n
(il dividendo ) e l'operando di destra d
(il divisore ) e produce il risultato q
(il quoziente ).
La divisione intera Java si arrotonda verso lo zero. La sezione 15.17.2 di JLS specifica il comportamento della divisione in intero Java come segue:
Il quoziente prodotto per gli operatori
n
ed
è un valore interoq
cui grandezza è la più grande possibile mentre soddisfa|d ⋅ q| ≤ |n|
. Inoltre,q
è positivo quando|n| ≥ |d|
en
ed
hanno lo stesso segno, maq
è negativo quando|n| ≥ |d|
en
ed
hanno segni opposti.
Ci sono un paio di casi speciali:
- Se
n
èMIN_VALUE
e il divisore è -1, si verifica un overflow di numero intero e il risultato èMIN_VALUE
. Nessuna eccezione è lanciata in questo caso. - Se
d
è 0, viene lanciata l'opzione ArithmeticException.
La divisione Java floating point ha altri casi da considerare. Tuttavia l'idea di base è che il risultato q
è il valore più vicino alla soddisfazione d . q = n
.
La divisione in virgola mobile non genererà mai un'eccezione. Invece, le operazioni che dividono per zero risultano in valori INF e NaN; vedi sotto.
Il significato di resto
A differenza di C e C ++, l'operatore rimanente in Java funziona con operazioni sia a interi che a virgola mobile.
Per i casi interi, il risultato di a % b
è definito come il numero r
tale che (a / b) * b + r
è uguale a a
, dove /
, *
e +
sono gli operatori di numero intero Java appropriati. Questo vale in tutti i casi tranne quando b
è zero. In quel caso, il resto risulta in ArithmeticException
.
Dalla definizione sopra riportata risulta che a % b
può essere negativa solo se a
è negativa, ed è positiva solo se a
è positiva. Inoltre, la grandezza di a % b
è sempre inferiore alla grandezza di b
.
L'operazione di resto del punto mobile è una generalizzazione del caso intero. Il risultato di a % b
è il resto r
è definito dalla relazione matematica r = a - (b ⋅ q)
dove:
-
q
è un numero intero, - è negativo solo se
a / b
è negativo e solo sea / b
è positivo, e - la sua grandezza è la più ampia possibile senza superare la grandezza del vero quoziente matematico di
a
eb
.
Il resto in virgola mobile può produrre valori INF
e NaN
in casi limite come quando b
è zero; vedi sotto. Non genererà un'eccezione.
Nota importante:
Il risultato di un'operazione remainder a virgola mobile come calcolata da
%
non è uguale a quella prodotta dall'operazione resto definita da IEEE 754. Il resto IEEE 754 può essere calcolato utilizzando il metodo di libreriaMath.IEEEremainder
.
Overflow intero
I valori interi Java 32 e 64 bit sono firmati e utilizzano la rappresentazione binaria a due complementi. Ad esempio, l'intervallo di numeri rappresentabili come (32 bit) int
-2 31 a +2 31 - 1.
Quando si aggiunge, si sottraggono o più due numeri interi a N bit (N == 32 o 64), il risultato dell'operazione potrebbe essere troppo grande per rappresentare un numero intero N bit. In questo caso, l'operazione porta a un overflow di numeri interi e il risultato può essere calcolato come segue:
- L'operazione matematica viene eseguita per fornire una rappresentazione intermedia del complemento a due dell'intero numero. Questa rappresentazione sarà più grande di N bit.
- Come risultato, vengono utilizzati i 32 o 64 bit inferiori della rappresentazione intermedia.
È necessario notare che l'overflow dei numeri interi non comporta eccezioni in nessuna circostanza.
Valori INF e NAN a virgola mobile
Java utilizza le rappresentazioni in virgola mobile IEE 754 per float
e double
. Queste rappresentazioni hanno alcuni valori speciali per rappresentare valori che non rientrano nel dominio dei numeri reali:
- I valori "infinito" o INF indicano numeri troppo grandi. Il valore
+INF
indica numeri troppo grandi e positivi. Il valore-INF
denota numeri troppo grandi e negativi. - Il "indefinito" / "non un numero" o NaN denotano valori derivanti da operazioni prive di significato.
I valori INF sono generati da operazioni mobili che causano un overflow, o dalla divisione per zero.
I valori NaN vengono prodotti dividendo zero per zero o calcolando zero resto zero.
Sorprendentemente, è possibile eseguire operazioni aritmetiche utilizzando gli operandi INF e NaN senza attivare eccezioni. Per esempio:
- Aggiungere + INF e un valore finito dà + INF.
- Aggiungere + INF e + INF dà + INF.
- Aggiungere + INF e -INF dà NaN.
- Dividere per INF fornisce +0.0 o -0.0.
- Tutte le operazioni con uno o più operandi NaN danno NaN.
Per i dettagli completi, fare riferimento alle sottosezioni rilevanti di JLS 15 . Si noti che questo è in gran parte "accademico". Per i calcoli tipici, un INF
o NaN
significa che qualcosa è andato storto; ad esempio, hai dati di input incompleti o errati o il calcolo è stato programmato in modo errato.
The Equality Operators (==,! =)
Gli operatori ==
e !=
Sono operatori binari che valutano true
o false
seconda che gli operandi siano uguali. L'operatore ==
restituisce true
se gli operandi sono uguali e false
altrimenti. L'operatore !=
Dà false
se gli operandi sono uguali e true
altrimenti.
Questi operatori possono essere utilizzati operandi con tipi primitivi e di riferimento, ma il comportamento è significativamente diverso. Secondo JLS, ci sono in realtà tre serie distinte di questi operatori:
- Gli operatori booleani
==
e!=
. - Gli operatori numerici
==
e!=
. - Gli operatori di riferimento
==
e!=
.
Tuttavia, in tutti i casi, il tipo di risultato degli operatori ==
e !=
È boolean
.
Gli operatori numerici ==
e !=
Quando uno (o entrambi) degli operandi di un operatore ==
o !=
È un tipo numerico primitivo ( byte
, short
, char
, int,
long
, float
o double
), l'operatore è un confronto numerico. Il secondo operando deve essere un tipo numerico primitivo o un tipo numerico in scatola.
Il comportamento di altri operatori numerici è il seguente:
- Se uno degli operandi è di tipo boxed, è unbox.
- Se uno degli operandi ora è un
byte
,short
ochar
, viene promosso a unint
. - Se i tipi di operandi non sono gli stessi, l'operando con il tipo "più piccolo" viene promosso al tipo "più grande".
- Il confronto viene quindi eseguito come segue:
- Se gli operandi promossi sono
int
olong
i valori vengono testati per vedere se sono identici. - Se gli operandi promossi sono
float
odouble
allora:- le due versioni di zero (
+0.0
e-0.0
) sono considerate uguali - un valore
NaN
viene trattato come non uguale a nulla, e - altri valori sono uguali se le loro rappresentazioni IEEE 754 sono identiche.
- le due versioni di zero (
- Se gli operandi promossi sono
Nota: è necessario fare attenzione quando si utilizza ==
e !=
Per confrontare i valori in virgola mobile.
Gli operatori booleani ==
e !=
Se entrambi gli operandi sono boolean
, o uno è boolean
e l'altro è Boolean
, questi operatori sono gli operatori booleani ==
e !=
. Il comportamento è il seguente:
- Se uno degli operandi è un
Boolean
, è unbox. - Gli operandi unbox vengono testati e il risultato booleano viene calcolato in base alla seguente tabella di verità
UN | B | A == B | A! = B |
---|---|---|---|
falso | falso | vero | falso |
falso | vero | falso | vero |
vero | falso | falso | vero |
vero | vero | vero | falso |
Ci sono due "trappole" che rendono consigliabile usare ==
e !=
parsimonia con valori di verità:
Se si utilizza
==
o!=
Per confrontare due oggettiBoolean
, vengono utilizzati gli operatori di riferimento. Questo potrebbe dare un risultato inaspettato; vedi Pitfall: usando == per confrontare oggetti di wrapper primitivi come IntegerL'operatore
==
può essere erroneamente digitato come=
. Per la maggior parte dei tipi di operandi, questo errore porta a un errore di compilazione. Tuttavia, perBoolean
operandiboolean
eBoolean
l'errore porta a comportamenti di runtime non corretti; see Pitfall - Usando '==' per testare un booleano
Gli operatori di riferimento ==
e !=
Se entrambi gli operandi sono riferimenti a oggetti, gli operatori ==
e !=
Testano se i due operandi si riferiscono allo stesso oggetto . Questo spesso non è quello che vuoi. Per verificare se due oggetti sono uguali per valore , dovrebbe essere usato il metodo .equals()
.
String s1 = "We are equal";
String s2 = new String("We are equal");
s1.equals(s2); // true
// WARNING - don't use == or != with String values
s1 == s2; // false
Avvertenza: l'uso di ==
e !=
Per confrontare i valori di String
non è corretto nella maggior parte dei casi; vedere http://www.Scriptutorial.com/java/example/16290/pitfall--using- to- compare- strings . Un problema simile si applica ai tipi di wrapper primitivi; vedi http://www.Scriptutorial.com/java/example/8996/pitfall--using- a- compare- primitive-wrappers- objects- such- as- integer .
Informazioni sui casi limite di NaN
JLS 15.21.1 afferma quanto segue:
Se uno degli operandi è
NaN
, il risultato di==
èfalse
ma il risultato di!=
Ètrue
. In effetti, il testx != x
ètrue
se e solo se il valore dix
èNaN
.
Questo comportamento è (per la maggior parte dei programmatori) inaspettato. Se si verifica se un valore NaN
è uguale a se stesso, la risposta è "No non lo è!". In altre parole, ==
non è riflessivo per i valori NaN
.
Tuttavia, questa non è una "stranezza" di Java, questo comportamento è specificato negli standard IEEE 754 a virgola mobile, e scoprirete che è implementato dalla maggior parte dei moderni linguaggi di programmazione. (Per ulteriori informazioni, consultare http://stackoverflow.com/a/1573715/139985 ... notando che questo è scritto da qualcuno che era "nella stanza quando sono state prese le decisioni"!)
Gli operatori di incremento / decremento (++ / -)
Le variabili possono essere incrementate o decrementate di 1 usando rispettivamente gli operatori ++
e --
.
Quando gli operatori ++
e --
seguono le variabili, sono chiamati rispettivamente post-incremento e post-decremento .
int a = 10;
a++; // a now equals 11
a--; // a now equals 10 again
Quando gli operatori ++
e --
precedono le variabili, le operazioni sono chiamate rispettivamente pre-incremento e pre-decremento .
int x = 10;
--x; // x now equals 9
++x; // x now equals 10
Se l'operatore precede la variabile, il valore dell'espressione è il valore della variabile dopo essere stato incrementato o decrementato. Se l'operatore segue la variabile, il valore dell'espressione è il valore della variabile prima di essere incrementato o decrementato.
int x=10;
System.out.println("x=" + x + " x=" + x++ + " x=" + x); // outputs x=10 x=10 x=11
System.out.println("x=" + x + " x=" + ++x + " x=" + x); // outputs x=11 x=12 x=12
System.out.println("x=" + x + " x=" + x-- + " x=" + x); // outputs x=12 x=12 x=11
System.out.println("x=" + x + " x=" + --x + " x=" + x); // outputs x=11 x=10 x=10
Fare attenzione a non sovrascrivere post-incrementi o decrementi. Ciò accade se si utilizza un operatore post-in / decrement alla fine di un'espressione che viene riassegnato alla variabile in / decrementata stessa. L'in / decremento non avrà effetto. Anche se la variabile sul lato sinistro viene incrementata correttamente, il suo valore verrà immediatamente sovrascritto con il risultato valutato in precedenza dal lato destro dell'espressione:
int x = 0;
x = x++ + 1 + x++; // x = 0 + 1 + 1
// do not do this - the last increment has no effect (bug!)
System.out.println(x); // prints 2 (not 3!)
Corretta:
int x = 0;
x = x++ + 1 + x; // evaluates to x = 0 + 1 + 1
x++; // adds 1
System.out.println(x); // prints 3
L'operatore condizionale (? :)
Sintassi
{condition-to-valutare} ? {statement-execution-on-true} : {istruzione-eseguito-su-falso}
Come mostrato nella sintassi, l'Operatore Condizionale (noto anche come Operatore Ternario 1 ) usa il ?
(punto interrogativo) e :
(due punti) caratteri per abilitare un'espressione condizionale di due possibili risultati. Può essere usato per sostituire i blocchi if-else
più lunghi per restituire uno dei due valori in base alla condizione.
result = testCondition ? value1 : value2
È equivalente a
if (testCondition) {
result = value1;
} else {
result = value2;
}
Può essere letto come "Se testCondition è vero, imposta il risultato su value1; altrimenti, imposta il risultato su value2 ".
Per esempio:
// get absolute value using conditional operator
a = -10;
int absValue = a < 0 ? -a : a;
System.out.println("abs = " + absValue); // prints "abs = 10"
È equivalente a
// get absolute value using if/else loop
a = -10;
int absValue;
if (a < 0) {
absValue = -a;
} else {
absValue = a;
}
System.out.println("abs = " + absValue); // prints "abs = 10"
Uso comune
È possibile utilizzare l'operatore condizionale per assegnazioni condizionali (come il controllo nullo).
String x = y != null ? y.toString() : ""; //where y is an object
Questo esempio è equivalente a:
String x = "";
if (y != null) {
x = y.toString();
}
Poiché l'operatore condizionale ha la seconda precedenza più bassa, al di sopra degli operatori di assegnazione , raramente è necessario utilizzare la parentesi intorno alla condizione , ma è necessaria una parentesi attorno all'intero costrutto dell'operatore condizionale quando combinato con altri operatori:
// no parenthesis needed for expressions in the 3 parts
10 <= a && a < 19 ? b * 5 : b * 7
// parenthesis required
7 * (a > 0 ? 2 : 5)
La nidificazione degli operatori condizionali può essere eseguita anche nella terza parte, dove funziona più come concatenare o come un'istruzione switch.
a ? "a is true" :
b ? "a is false, b is true" :
c ? "a and b are false, c is true" :
"a, b, and c are false"
//Operator precedence can be illustrated with parenthesis:
a ? x : (b ? y : (c ? z : w))
Nota:
1 - Sia Java Language Specification che Java Tutorial chiamano l'operatore ( ? :
:) L'operatore condizionale . Il Tutorial dice che è "noto anche come Operatore Ternario" poiché è (attualmente) l'unico operatore ternario definito da Java. La terminologia "Operatore condizionale" è coerente con C e C ++ e altre lingue con un operatore equivalente.
Gli operatori bitwise e logici (~, &, |, ^)
Il linguaggio Java fornisce 4 operatori che eseguono operazioni bit a bit o logiche su operandi interi o booleani.
- L'operatore complementare (
~
) è un operatore unario che esegue un'inversione bit per bit o logica dei bit di un operando; vedi JLS 15.15.5. . - L'operatore AND (
&
) è un operatore binario che esegue un "e" logico o bit a bit di due operandi; vedi JLS 15.22.2. . - L'operatore OR (
|
) è un operatore binario che esegue un "inclusivo" o "logico" di bit di due operandi; vedi JLS 15.22.2. . - L'operatore XOR (
^
) è un operatore binario che esegue un "esclusivo o" bitwise o logico di due operandi; vedi JLS 15.22.2. .
Le operazioni logiche eseguite da questi operatori quando gli operandi sono booleani possono essere riassunte come segue:
UN | B | ~ A | A & B | A | B | A ^ B |
---|---|---|---|---|---|
0 | 0 | 1 | 0 | 0 | 0 |
0 | 1 | 1 | 0 | 1 | 1 |
1 | 0 | 0 | 0 | 1 | 1 |
1 | 1 | 0 | 1 | 1 | 0 |
Nota che per gli operandi interi, la tabella sopra descrive cosa succede per i singoli bit. Gli operatori operano effettivamente su tutti i 32 o 64 bit dell'operando o degli operandi in parallelo.
Tipi di operandi e tipi di risultato.
Le normali conversioni aritmetiche si applicano quando gli operandi sono numeri interi. Casi d'uso comuni per gli operatori bit a bit
L'operatore ~
viene utilizzato per invertire un valore booleano o modificare tutti i bit in un operando intero.
L'operatore &
viene usato per "mascherare" alcuni dei bit in un operando intero. Per esempio:
int word = 0b00101010;
int mask = 0b00000011; // Mask for masking out all but the bottom
// two bits of a word
int lowBits = word & mask; // -> 0b00000010
int highBits = word & ~mask; // -> 0b00101000
Il |
l'operatore è usato per combinare i valori di verità di due operandi. Per esempio:
int word2 = 0b01011111;
// Combine the bottom 2 bits of word1 with the top 30 bits of word2
int combined = (word & mask) | (word2 & ~mask); // -> 0b01011110
L'operatore ^
viene utilizzato per alternare o "sfogliare" i bit:
int word3 = 0b00101010;
int word4 = word3 ^ mask; // -> 0b00101001
Per ulteriori esempi sull'uso degli operatori bit a bit, vedere Manipolazione bit
L'istanza di operatore
Questo operatore controlla se l'oggetto è di un particolare tipo di classe / interfaccia. L' operatore instanceof è scritto come:
( Object reference variable ) instanceof (class/interface type)
Esempio:
public class Test {
public static void main(String args[]){
String name = "Buyya";
// following will return true since name is type of String
boolean result = name instanceof String;
System.out.println( result );
}
}
Ciò produrrebbe il seguente risultato:
true
Questo operatore restituirà comunque true se l'oggetto da confrontare è l'assegnazione compatibile con il tipo sulla destra.
Esempio:
class Vehicle {}
public class Car extends Vehicle {
public static void main(String args[]){
Vehicle a = new Car();
boolean result = a instanceof Car;
System.out.println( result );
}
}
Ciò produrrebbe il seguente risultato:
true
The Assignment Operators (=, + =, - =, * =, / =,% =, << =, >> =, >>> =, & =, | = e ^ =)
L'operando di sinistra per questi operatori deve essere una variabile non finale o un elemento di una matrice. L'operando destro deve essere compatibile con l'operando di sinistra. Ciò significa che i tipi devono essere uguali oppure che il tipo di operando destro deve essere convertibile nel tipo di operandi di sinistra mediante una combinazione di boxing, unboxing o widening. (Per i dettagli completi, fare riferimento a JLS 5.2 .)
Il significato preciso degli operatori "operazione e assegnazione" è specificato da JLS 15.26.2 come:
Un'espressione di assegnazione composta della forma
E1 op= E2
è equivalente aE1 = (T) ((E1) op (E2))
, doveT
è il tipo diE1
, tranne cheE1
viene valutato solo una volta.
Nota che c'è un cast implicito del tipo prima dell'assegnazione finale.
1. =
L'operatore di assegnazione semplice: assegna il valore dell'operando di destra all'operando di sinistra.
Esempio:
c = a + b
aggiungerà il valore dia + b
al valore dic
e assegnarlo ac
2. +=
L'operatore "aggiungi e assegna": aggiunge il valore dell'operando di destra al valore dell'operando di sinistra e assegna il risultato all'operando di sinistra. Se l'operando di sinistra ha tipo String
, allora questo è un operatore "concatena e assegna".
Esempio:
c += a
è all'incirca uguale ac = c + a
3. -=
L'operatore "sottrazione e assegnazione": sottrae il valore dell'operando di destra dal valore dell'operando della mano sinistra e assegna il risultato all'operando della mano sinistra.
Esempio:
c -= a
è all'incirca uguale ac = c - a
4. *=
L'operatore "moltiplica e assegna": moltiplica il valore dell'operando di destra per il valore dell'operando di sinistra e assegna il risultato all'operando di sinistra. .
Esempio:
c *= a
è all'incirca uguale ac = c * a
5. /=
L'operatore "divide e assegna": divide il valore dell'operando di destra per il valore dell'operando di sinistra e assegna il risultato all'operando di sinistra.
Esempio:
c /*= a
è approssimativamente uguale ac = c / a
6. %=
L'operatore "modulus and assign": calcola il modulo del valore dell'operando di destra per il valore dell'operando di sinistra e assegna il risultato all'operando di sinistra.
Esempio:
c %*= a
è approssimativamente uguale ac = c % a
7. <<=
L'operatore "spostamento a sinistra e assegnazione".
Esempio:
c <<= 2
equivale all'incirca ac = c << 2
8. >>=
L'operatore "aritmetico destro cambia e assegna".
Esempio:
c >>= 2
equivale all'incirca ac = c >> 2
9. >>>=
L'operatore "spostamento logico destro e assegnazione".
Esempio:
c >>>= 2
equivale all'incirca ac = c >>> 2
10. &=
L'operatore "bit a bit e assegnazione".
Esempio:
c &= 2
è approssimativamente uguale ac = c & 2
11. |=
L'operatore "bit a bit o assign".
Esempio:
c |= 2
equivale all'incirca ac = c | 2
12. ^=
L'operatore "bitwise exclusive or and assign".
Esempio:
c ^= 2
equivale all'incirca ac = c ^ 2
Gli operatori condizionali e condizionali o (&& e ||)
Java fornisce un operatore condizionale e / o condizionale, che entrambi accettano uno o due operandi di tipo boolean
e producono un risultato boolean
. Questi sono:
&&
- l'operatore AND condizionale,||
- gli operatori OR condizionali. La valutazione di<left-expr> && <right-expr>
è equivalente al seguente pseudo-codice:{ boolean L = evaluate(<left-expr>); if (L) { return evaluate(<right-expr>); } else { // short-circuit the evaluation of the 2nd operand expression return false; } }
La valutazione di <left-expr> || <right-expr>
è equivalente al seguente pseudo-codice:
{
boolean L = evaluate(<left-expr>);
if (!L) {
return evaluate(<right-expr>);
} else {
// short-circuit the evaluation of the 2nd operand expression
return true;
}
}
Come illustrato dallo pseudo-codice sopra, il comportamento degli operatori di cortocircuito è equivalente all'utilizzo delle istruzioni if
/ else
.
Esempio: uso di && come guardia in un'espressione
L'esempio seguente mostra il modello di utilizzo più comune per l'operatore &&
. Confrontare queste due versioni di un metodo per verificare se un Integer
fornito è zero.
public boolean isZero(Integer value) {
return value == 0;
}
public boolean isZero(Integer value) {
return value != null && value == 0;
}
La prima versione funziona nella maggior parte dei casi, ma se l'argomento value
è null
, verrà NullPointerException
una NullPointerException
.
Nella seconda versione abbiamo aggiunto un test di "guardia". Il value != null && value == 0
espressione viene valutata eseguendo prima il value != null
test. Se il test null
esito positivo (vale a dire vale true
), viene valutato il value == 0
espressione. Se il test null
fallisce, allora la valutazione del value == 0
viene saltata (cortocircuitata) e non si ottiene NullPointerException
.
Esempio: usare && per evitare un calcolo costoso
L'esempio seguente mostra come &&
può essere usato per evitare un calcolo relativamente costoso:
public boolean verify(int value, boolean needPrime) {
return !needPrime | isPrime(value);
}
public boolean verify(int value, boolean needPrime) {
return !needPrime || isPrime(value);
}
Nella prima versione, entrambi gli operandi del |
sarà sempre valutato, quindi il metodo (costoso) isPrime
verrà chiamato inutilmente. La seconda versione evita la chiamata non necessaria utilizzando ||
invece di |
.
The Shift Operators (<<, >> e >>>)
Il linguaggio Java fornisce tre operatori per eseguire lo spostamento bit per bit su valori interi a 32 e 64 bit. Questi sono tutti operatori binari con il primo operando come valore da spostare, e il secondo operando che dice quanto lontano spostare.
L'operatore
<<
o spostamento a sinistra sposta il valore dato dal primo operando verso sinistra per il numero di posizioni di bit date dal secondo operando. Le posizioni vuote all'estremità destra sono piene di zeri.L'operatore '>>' o spostamento aritmetico sposta il valore dato dal primo operando a destra del numero di posizioni di bit date dal secondo operando. Le posizioni vuote all'estremità sinistra vengono riempite copiando il bit più a sinistra. Questo processo è noto come estensione del segno .
L'operatore ">>>" o spostamento logico destro sposta il valore dato dal primo operando a destra del numero di posizioni di bit fornite dal secondo operando. Le posizioni vuote all'estremità sinistra sono piene di zeri.
Gli appunti:
Questi operatori richiedono un valore
int
olong
come primo operando e producono un valore con lo stesso tipo del primo operando. (Sarà necessario utilizzare un cast di tipo esplicito quando si assegna il risultato di uno spostamento a una variabilebyte
,short
ochar
.)Se si utilizza un operatore di spostamento con un primo operando che è un
byte
,char
oshort
, viene promosso a unint
e l'operazione produce unint
.)Il secondo operando viene ridotto modulo il numero di bit dell'operazione per dare l'ammontare dello spostamento. Per ulteriori informazioni sul concetto matematico mod , vedere Esempi di moduli .
I bit che vengono spostati dalla fine sinistra o destra dall'operazione vengono scartati. (Java non fornisce un operatore di "rotazione" primitivo).
L'operatore di spostamento aritmetico equivale a dividere un numero (a complemento di due) per una potenza di 2.
L'operatore di spostamento a sinistra equivale a moltiplicare un numero (a complemento di due) per una potenza di 2.
La seguente tabella ti aiuterà a vedere gli effetti dei tre operatori di turno. (I numeri sono stati espressi in notazione binaria per aiutare la visualizzazione).
operand1 | operando2 | << | >> | >>> |
---|---|---|---|---|
0b0000000000001011 | 0 | 0b0000000000001011 | 0b0000000000001011 | 0b0000000000001011 |
0b0000000000001011 | 1 | 0b0000000000010110 | 0b0000000000000101 | 0b0000000000000101 |
0b0000000000001011 | 2 | 0b0000000000101100 | 0b0000000000000010 | 0b0000000000000010 |
0b0000000000001011 | 28 | 0b1011000000000000 | 0b0000000000000000 | 0b0000000000000000 |
0b0000000000001011 | 31 | 0b1000000000000000 | 0b0000000000000000 | 0b0000000000000000 |
0b0000000000001011 | 32 | 0b0000000000001011 | 0b0000000000001011 | 0b0000000000001011 |
... | ... | ... | ... | ... |
0b1000000000001011 | 0 | 0b1000000000001011 | 0b1000000000001011 | 0b1000000000001011 |
0b1000000000001011 | 1 | 0b0000000000010110 | 0b1100000000000101 | 0b0100000000000101 |
0b1000000000001011 | 2 | 0b0000000000101100 | 0b1110000000000010 | 0b00100000000000100 |
0b1000000000001011 | 31 | 0b1000000000000000 | 0b1111111111111111 | 0b0000000000000001 |
Ci sono esempi di utenti di operatori di shift nella manipolazione di Bit
L'operatore Lambda (->)
Da Java 8 in poi, l'operatore Lambda ( ->
) è l'operatore utilizzato per introdurre un'espressione Lambda. Esistono due sintassi comuni, come illustrato da questi esempi:
a -> a + 1 // a lambda that adds one to its argument
a -> { return a + 1; } // an equivalent lambda using a block.
Un'espressione lambda definisce una funzione anonima, o più correttamente un'istanza di una classe anonima che implementa un'interfaccia funzionale .
(Questo esempio è incluso qui per completezza. Fare riferimento all'argomento Lambda Expressions per il trattamento completo.)
The Relational Operators (<, <=,>,> =)
Gli operatori <
, <=
, >
e >=
sono operatori binari per il confronto di tipi numerici. Il significato degli operatori è come ci si aspetterebbe. Ad esempio, se a
e b
sono dichiarati come byte
, short
, char
, int
, long
, float
, double
o i corrispondenti tipi di box:
- `a < b` tests if the value of `a` is less than the value of `b`.
- `a <= b` tests if the value of `a` is less than or equal to the value of `b`.
- `a > b` tests if the value of `a` is greater than the value of `b`.
- `a >= b` tests if the value of `a` is greater than or equal to the value of `b`.
Il tipo di risultato per questi operatori è boolean
in tutti i casi.
Gli operatori relazionali possono essere utilizzati per confrontare i numeri con tipi diversi. Per esempio:
int i = 1;
long l = 2;
if (i < l) {
System.out.println("i is smaller");
}
Gli operatori relazionali possono essere utilizzati quando uno o entrambi i numeri sono esempi di tipi numerici in scatola. Per esempio:
Integer i = 1; // 1 is autoboxed to an Integer
Integer j = 2; // 2 is autoboxed to an Integer
if (i < j) {
System.out.println("i is smaller");
}
Il comportamento preciso è riassunto come segue:
- Se uno degli operandi è di tipo boxed, è unbox.
- Se uno degli operandi ora è un
byte
,short
ochar
, viene promosso a unint
. - Se i tipi di operandi non sono gli stessi, l'operando con il tipo "più piccolo" viene promosso al tipo "più grande".
- Il confronto viene eseguito sui valori
int
,long
,float
odouble
risultanti.
Devi stare attento con i confronti relazionali che coinvolgono numeri in virgola mobile:
- Le espressioni che calcolano i numeri in virgola mobile spesso causano errori di arrotondamento dovuti al fatto che le rappresentazioni in virgola mobile del computer hanno una precisione limitata.
- Quando si confronta un tipo intero e un tipo a virgola mobile, anche la conversione del numero intero in virgola mobile può portare a errori di arrotondamento.
Infine, Java supporta bit l'uso di operatori relazionali con tipi diversi da quelli sopra elencati. Ad esempio, non è possibile utilizzare questi operatori per confrontare stringhe, matrici di numeri e così via.