Zoeken…


Invoering

Operators in de programmeertaal Java zijn speciale symbolen die specifieke bewerkingen uitvoeren op een, twee of drie operanden en vervolgens een resultaat retourneren.

Opmerkingen

Een operator is een symbool (of symbolen) dat een Java-programma vertelt een bewerking uit te voeren op één, twee of drie operanden . Een operator en zijn operanden vormen een uitdrukking (zie het onderwerp Uitdrukkingen). De operanden van een operator zijn zelf uitdrukkingen.

Dit onderwerp beschrijft de ongeveer 40 verschillende operatoren die door Java zijn gedefinieerd. In het afzonderlijke onderwerp Uitdrukkingen wordt uitgelegd:

  • hoe operatoren, operanden en andere dingen worden gecombineerd tot expressies,
  • hoe de uitdrukkingen worden geëvalueerd, en
  • hoe typen, conversies en evaluatie van expressies werken.

The String Concatenation Operator (+)

Het symbool + kan drie verschillende operatoren in Java betekenen:

  • Als er geen operand vóór de + , is het de unary Plus-operator.
  • Als er twee operanden zijn en beide numeriek zijn. dan is het de binaire toevoeging operator.
  • Als er twee operanden zijn, en ten minste een daarvan is een String , dan is het de binaire aaneenschakelaar.

In het eenvoudige geval voegt de operator Concatenation twee reeksen samen om een derde reeks te geven. Bijvoorbeeld:

String s1 = "a String";
String s2 = "This is " + s1;    // s2 contains "This is a String"

Wanneer een van de twee operanden geen tekenreeks is, wordt deze als volgt geconverteerd naar een String :

  • Een operand waarvan het type een primitief type is, wordt omgezet alsof door toString() aan te roepen op de waarde in het kader.

  • Een operand waarvan het type een referentietype is, wordt geconverteerd door de methode toString() de operand aan te roepen. Als de operand null , of als de methode toString() null retourneert, wordt in plaats daarvan de tekenreeks letterlijk "null" gebruikt.

Bijvoorbeeld:

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"

De verklaring voor het voorbeeld s5 is dat de methode toString() op arraytypen is overgenomen van java.lang.Object en dat het gedrag bestaat uit het produceren van een tekenreeks die bestaat uit de typenaam en de identiteitshashcode van het object.

De operator Concatenation is opgegeven om een nieuw String object te maken, behalve in het geval dat de expressie een constante expressie is. In het laatste geval wordt de uitdrukking geëvalueerd op compileertype en is de looptijdwaarde gelijk aan een letterlijke tekenreeks. Dit betekent dat er geen runtime overhead is bij het splitsen van een lange reeks letterlijke tekens zoals deze:

String typing = "The quick brown fox " +
                "jumped over the " +
                "lazy dog";           // constant expression

Optimalisatie en efficiëntie

Zoals hierboven is opgemerkt, wordt met uitzondering van constante expressies elke string-aaneenschakelingsexpressie een nieuw String object gemaakt. Beschouw deze code:

public String stars(int count) {
    String res = "";
    for (int i = 0; i < count; i++) {
        res = res + "*";
    }
    return res;
}

In de bovenstaande methode maakt elke iteratie van de lus een nieuwe String die één teken langer is dan de vorige iteratie. Elke aaneenschakeling kopieert alle tekens in de operandstrings om de nieuwe String te vormen. Zo zullen stars(N) :

  • maak N nieuwe String objecten en gooi alles behalve de laatste weg,
  • kopieer N * (N + 1) / 2 tekens, en
  • genereer O(N^2) afval.

Dit is erg duur voor grote N Inderdaad, elke code die tekenreeksen in een lus samenvoegt, kan dit probleem hebben. Een betere manier om dit te schrijven is als volgt:

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();
}

Idealiter zou u de capaciteit van de StringBuilder moeten instellen, maar als dit niet praktisch is, zal de klasse automatisch de achtergrondarray laten groeien die de bouwer gebruikt om tekens te bevatten. (Opmerking: de implementatie breidt de achtergrondarray exponentieel uit. Deze strategie houdt zoveel kopieën van tekens over naar een O(N) plaats van O(N^2) .)

Sommige mensen passen dit patroon toe op alle tekenreeksen. Dit is echter niet nodig omdat de JLS een Java-compiler toestaat om string-aaneenschakelingen binnen een enkele expressie te optimaliseren. Bijvoorbeeld:

String s1 = ...;
String s2 = ...;    
String test = "Hello " + s1 + ". Welcome to " + s2 + "\n";

wordt meestal geoptimaliseerd door de bytecode-compiler tot zoiets;

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();

(De JIT-compiler kan dat verder optimaliseren als het kan afleiden dat s1 of s2 niet null kan zijn.) Maar merk op dat deze optimalisatie alleen binnen een enkele expressie is toegestaan.

Kortom, als u zich zorgen maakt over de efficiëntie van tekenreeksen:

  • Doe hand-optimalisatie als u herhaalde aaneenschakeling in een lus (of vergelijkbaar) doet.
  • Optimaliseer geen enkele aaneenschakelingsexpressie.

De rekenkundige operatoren (+, -, *, /,%)

De Java-taal biedt 7 operatoren die rekenen op gehele en drijvende komma waarden.

  • Er zijn twee + operators:
    • De operator voor binaire optelling voegt een nummer toe aan een ander. (Er is ook een binaire + operator die tekenreeksen samenvoegt. Dat wordt in een apart voorbeeld beschreven.)
    • De operator Unary plus doet niets anders dan het activeren van numerieke promotie (zie hieronder)
  • Er zijn twee - operatoren:
    • De binaire aftrekoperator trekt een nummer af van een ander.
    • De unaire min-operator komt overeen met het aftrekken van de operand van nul.
  • De binaire vermenigvuldiger (*) vermenigvuldigt een getal met een ander.
  • De operator voor binair delen (/) deelt het ene getal door het andere.
  • De operator binaire rest 1 (%) berekent de rest wanneer een nummer wordt gedeeld door een ander.

1. Dit wordt vaak ten onrechte de "modulus" -operator genoemd. "Rest" is de term die wordt gebruikt door de JLS. "Modulus" en "rest" zijn niet hetzelfde.

Operand- en resultatietypen en numerieke promotie

De operatoren vereisen numerieke operanden en produceren numerieke resultaten. De operandtypen kunnen elk primitief numeriek type zijn (dwz byte , short , char , int , long , float of double ) of elk numeriek wrapper-type definiëren in java.lang ; dat wil zeggen ( Byte , Character , Short , Integer , Long , Float of Double .

Het resultaattype wordt als volgt bepaald op basis van de typen operand of operanden:

  • Als een van de operanden een double of Double , is het resultaattype double .
  • Als een van de operanden een float of Float , is het resultaattype float .
  • Anders is het resultaattype long als een van de operanden long of Long is.
  • Anders is het resultaattype int . Dit omvat byte , short en char operands evenals `int.

Het resultaattype van de bewerking bepaalt hoe de rekenkundige bewerking wordt uitgevoerd en hoe de operanden worden verwerkt

  • Als het resultaattype double , worden de operanden gepromoveerd tot double en wordt de bewerking uitgevoerd met 64-bits (dubbel precisie binaire) IEE 754 rekenkunde met drijvende komma.
  • Als het resultaat float , worden de operanden bevorderd tot float en de bewerking wordt uitgevoerd 32-bits (één nauwkeurige binair) IEE 754 drijvende komma.
  • Als het resultaattype long , worden de operanden te long gepromoveerd en wordt de bewerking uitgevoerd met 64-bits ondertekende tweevoudige complementaire binaire integer rekenkunde.
  • Als het resultaattype int , worden de operanden gepromoveerd tot int en wordt de bewerking uitgevoerd met behulp van 32-bits ondertekende twee-complement binaire integer rekenkunde.

Promotie wordt uitgevoerd in twee fasen:

  • Als het operandtype een wrapper-type is, wordt de operand-waarde unboxed naar een waarde van het overeenkomstige primitieve type.
  • Indien nodig wordt het primitieve type gepromoveerd tot het vereiste type:
    • Bevordering van gehele getallen aan int of long verliesgevend is minder.
    • Promotie van float naar double is verliesloos.
    • Promotie van een geheel getal tot een waarde met drijvende komma kan leiden tot verlies van precisie. De conversie wordt uitgevoerd met behulp van IEE 768 "rond-naar-dichtstbijzijnde" semantiek.

De betekenis van deling

De operator / deelt de linker operand n (het dividend ) en de rechter operand d (de deler ) en produceert het resultaat q (het quotiënt ).

Java integer divisie rondt af naar nul. De JLS-sectie 15.17.2 specificeert het gedrag van de Java-gehele getallenverdeling als volgt:

Het quotiënt dat wordt geproduceerd voor operanden n en d is een geheel getal q waarvan de grootte zo groot mogelijk is terwijl wordt voldaan aan |d ⋅ q| ≤ |n| . Bovendien is q positief wanneer |n| ≥ |d| en n en d hebben hetzelfde teken, maar q is negatief wanneer |n| ≥ |d| en n en d hebben tegengestelde tekens.

Er zijn een paar speciale gevallen:

  • Als de n MIN_VALUE is en de deler -1 is, dan treedt een integeroverloop op en is het resultaat MIN_VALUE . In dit geval wordt geen uitzondering gemaakt.
  • Als d 0 is, wordt `ArithmeticException gegenereerd.

Java drijvende komma verdeling heeft meer randgevallen te overwegen. Het basisidee is echter dat het resultaat q de waarde is die het dichtst in de buurt komt van d . q = n .

Drijvende komma-verdeling zal nooit leiden tot een uitzondering. In plaats daarvan resulteren bewerkingen die door nul delen in INF- en NaN-waarden; zie hieronder.

De betekenis van de rest

In tegenstelling tot C en C ++ werkt de restoperator in Java met zowel gehele getallen als drijvende-kommabewerkingen.

Voor gehele getallen wordt het resultaat van a % b gedefinieerd als het getal r zodat (a / b) * b + r gelijk is aan a , waarbij / , * en + de juiste Java-integeroperatoren zijn. Dit geldt in alle gevallen behalve wanneer b nul is. In dat geval resulteert de rest in een ArithmeticException .

Uit de bovenstaande definitie volgt dat a % b alleen negatief kan zijn als a negatief is en alleen positief als a positief is. Bovendien is de grootte van a % b altijd kleiner dan de grootte van b .

De drijvende-komma-restoperatie is een generalisatie van het gehele getal. Het resultaat van a % b is de rest r wordt gedefinieerd door de wiskundige relatie r = a - (b ⋅ q) waarbij:

  • q is een geheel getal,
  • het is alleen negatief als a / b negatief is positief alleen als a / b positief is, en
  • zijn grootte is zo groot mogelijk zonder de grootte van het ware wiskundige quotiënt van a en b te overschrijden.

De rest van het drijvende punt kan INF en NaN waarden produceren in INF , bijvoorbeeld wanneer b nul is; zie hieronder. Het zal geen uitzondering veroorzaken.

Belangrijke notitie:

Het resultaat van een drijvende-komma restbewerking zoals berekend door % is niet hetzelfde als dat geproduceerd door de Math.IEEEremainder gedefinieerd door IEEE 754. De IEEE 754 rest kan worden berekend met behulp van de Math.IEEEremainder bibliotheekmethode.

Integer Overflow

Java 32- en 64-bits gehele getallen worden ondertekend en gebruiken tweevoudige complementaire binaire weergave. Bijvoorbeeld, het bereik van getallen dat kan worden weergegeven als (32 bit) int -2 31 tot +2 31 - 1.

Wanneer u twee N-bits gehele getallen optelt, aftrekt of meerdere (N == 32 of 64), kan het resultaat van de bewerking te groot zijn om als een N-bits geheel getal weer te geven. In dit geval leidt de bewerking tot een overloop van gehele getallen en kan het resultaat als volgt worden berekend:

  • De wiskundige bewerking wordt uitgevoerd om een tussentijdse twee-complement weergave van het gehele getal te geven. Deze weergave zal groter zijn dan N bits.
  • De onderste 32 of 64 bits van de tussenliggende weergave worden als resultaat gebruikt.

Opgemerkt moet worden dat integer overflow onder geen enkele omstandigheid resulteert in uitzonderingen.

Zwevende punt INF- en NAN-waarden

Java gebruikt IEE 754 drijvende-komma-representaties voor float en double . Deze representaties hebben enkele speciale waarden voor het representeren van waarden die buiten het domein van reële getallen vallen:

  • De "oneindige" of INF-waarden geven te grote getallen aan. De waarde +INF te grote en positieve getallen aan. De -INF waarde geeft te grote en negatieve getallen aan.
  • De "onbepaalde tijd" / "geen getal" of NaN geven waarden aan die voortvloeien uit betekenisloze bewerkingen.

De INF-waarden worden geproduceerd door zwevende bewerkingen die overloop veroorzaken, of door deling door nul.

De NaN-waarden worden geproduceerd door nul door nul te delen, of door nul te berekenen als overblijvende nul.

Verrassend genoeg is het mogelijk rekenkunde uit te voeren met INF- en NaN-operanden zonder uitzonderingen te activeren. Bijvoorbeeld:

  • Het toevoegen van + INF en een eindige waarde geeft + INF.
  • Het toevoegen van + INF en + INF geeft + INF.
  • Het toevoegen van + INF en -INF geeft NaN.
  • Delen door INF geeft +0,0 of -0,0.
  • Alle bewerkingen met een of meer NaN-operanden geven NaN.

Raadpleeg de relevante paragrafen van JLS 15 voor meer informatie . Merk op dat dit grotendeels "academisch" is. Voor typische berekeningen betekent een INF of NaN dat er iets fout is gegaan; u hebt bijvoorbeeld onvolledige of onjuiste invoergegevens of de berekening is verkeerd geprogrammeerd.

De gelijkheidsexploitanten (==,! =)

De operatoren == en != Zijn binaire operatoren die evalueren true of false afhankelijk van of de operanden gelijk zijn. De operator == geeft true als de operanden anders gelijk en false zijn. De operator != Geeft false als de operanden gelijk zijn en anders true zijn.

Deze operatoren kunnen operanden met primitieve en referentietypes worden gebruikt, maar het gedrag is aanzienlijk verschillend. Volgens de JLS zijn er eigenlijk drie verschillende sets van deze operators:

  • De Boolean == en != Operatoren.
  • De operatoren Numeriek == en != .
  • De operatoren Reference == en != .

In alle gevallen is het resultaattype van de operatoren == en != Echter boolean .

De operatoren Numeriek == en !=

Wanneer een (of beide) van de operanden van een operator == of != Een primitief numeriek type is ( byte , short , char , int, long , float of double ), is de operator een numerieke vergelijking. De tweede operand moet een primitief numeriek type of een omkaderd numeriek type zijn.

Het gedrag van andere numerieke operatoren is als volgt:

  1. Als een van de operanden van het type boxed is, wordt het unboxed.
  2. Als een van de operanden nu een byte , short of char , wordt deze gepromoveerd tot een int .
  3. Als de typen operanden niet hetzelfde zijn, wordt de operand met het "kleinere" type bevorderd tot het "grotere" type.
  4. De vergelijking wordt vervolgens als volgt uitgevoerd:
    • Als de gepromote operanden int of long zijn, worden de waarden getest om te zien of ze identiek zijn.
    • Als de gepromote operanden float of double dan:
      • de twee versies van nul ( +0.0 en -0.0 ) worden als gelijk behandeld
      • een NaN waarde wordt behandeld als niet gelijk aan iets, en
      • andere waarden zijn gelijk als hun IEEE 754-representaties identiek zijn.

Opmerking: u moet voorzichtig zijn wanneer u == en != == om drijvende-kommawaarden te vergelijken.

De Boolean == en != Operatoren

Als beide operanden boolean , of de ene is boolean en de andere is Boolean , deze operatoren de Boolean == en != Operatoren. Het gedrag is als volgt:

  1. Als een van de operanden een Boolean , wordt het uit de box gehaald.
  2. De niet-omkaderde operanden worden getest en het Booleaanse resultaat wordt berekend volgens de volgende waarheidstabel
EEN B A == B A! = B
vals vals waar vals
vals waar vals waar
waar vals vals waar
waar waar waar vals

Er zijn twee "valkuilen" die het raadzaam maken om == en != Spaarzaam met waarheidswaarden te gebruiken:

De operatoren Reference == en !=

Als beide operanden objectverwijzingen zijn, testen de operatoren == en != Of de twee operanden naar hetzelfde object verwijzen . Dit is vaak niet wat je wilt. Om te testen of twee objecten gelijk zijn aan waarde , moet in plaats daarvan de methode .equals() worden gebruikt.

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

Waarschuwing: het gebruik van == en != Om String te vergelijken is in de meeste gevallen onjuist ; zie http://www.riptutorial.com/java/example/16290/pitfall--using----to-compare-strings . Een soortgelijk probleem is van toepassing op primitieve wikkeltypen; zie http://www.riptutorial.com/java/example/8996/pitfall--using----to-compare-primitive-wrappers-objects-such-as-integer .

Over de randgevallen van NaN

JLS 15.21.1 stelt het volgende:

Als een operand NaN , is het resultaat van == false maar het resultaat van != Is true . De test x != x is true waar en alleen als de waarde van x NaN .

Dit gedrag is (voor de meeste programmeurs) onverwacht. Als u test of een NaN waarde gelijk is aan zichzelf, is het antwoord "Nee, dat is het niet!". Met andere woorden, == is niet reflexief voor NaN waarden.

Dit is echter geen Java-"eigenaardigheid", dit gedrag wordt gespecificeerd in de IEEE 754 floating-point standaarden en u zult merken dat het wordt geïmplementeerd door de meeste moderne programmeertalen. (Zie http://stackoverflow.com/a/1573715/139985 voor meer informatie ... en merk op dat dit is geschreven door iemand die "in de kamer was toen de beslissingen werden genomen"!)

De operators voor verhogen / verlagen (++ / -)

Variabelen kunnen met 1 worden verhoogd of verlaagd met respectievelijk de operatoren ++ en -- .

Wanneer de operatoren ++ en -- variabelen volgen, worden ze respectievelijk post-increment en post-decrement genoemd.

int a = 10;
a++; // a now equals 11
a--; // a now equals 10 again

Wanneer de operatoren ++ en -- voorafgaan aan de variabelen, worden de bewerkingen respectievelijk pre-increment en pre-decrement genoemd.

int x = 10;
--x; // x now equals 9
++x; // x now equals 10

Als de operator de variabele voorafgaat, is de waarde van de uitdrukking de waarde van de variabele nadat deze is verhoogd of verlaagd. Als de operator de variabele volgt, is de waarde van de uitdrukking de waarde van de variabele voordat deze wordt verhoogd of verlaagd.

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

Let op dat u geen post-toenames of afnames overschrijft. Dit gebeurt als u een post-in / decrement-operator gebruikt aan het einde van een expressie die opnieuw wordt toegewezen aan de in / decremented-variabele zelf. Het verhogen / verlagen heeft geen effect. Hoewel de variabele aan de linkerkant correct wordt verhoogd, wordt de waarde ervan onmiddellijk overschreven door het eerder geëvalueerde resultaat aan de rechterkant van de uitdrukking:

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!) 

Correct:

int x = 0;
x = x++ + 1 + x;        // evaluates to x = 0 + 1 + 1
x++;                    // adds 1
System.out.println(x);  // prints 3 

De voorwaardelijke operator (? :)

Syntaxis

{voorwaarde om te evalueren} ? {statement-execution-on-true} : {statement-execution-on-false}

Zoals weergegeven in de syntaxis, gebruikt de voorwaardelijke operator (ook bekend als de Ternary Operator 1 ) de ? (vraagteken) en : (dubbele punt) tekens om een voorwaardelijke uitdrukking van twee mogelijke uitkomsten mogelijk te maken. Het kan worden gebruikt om langere if-else blokken te vervangen om een van twee waarden te retourneren op basis van voorwaarde.

result = testCondition ? value1 : value2

Is gelijk aan

if (testCondition) { 
    result = value1; 
} else { 
    result = value2; 
}

Het kan gelezen worden als “Als testCondition waar is, zet resultaat op waarde1; zet anders het resultaat op waarde2 ”.

Bijvoorbeeld:

// get absolute value using conditional operator 
a = -10;
int absValue = a < 0 ? -a : a;
System.out.println("abs = " + absValue); // prints "abs = 10"

Is gelijk aan

// 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"

Normaal gebruik

U kunt de voorwaardelijke operator gebruiken voor voorwaardelijke toewijzingen (zoals nulcontrole).

String x = y != null ? y.toString() : ""; //where y is an object

Dit voorbeeld is gelijk aan:

String x = "";

if (y != null) {
    x = y.toString();
}

Aangezien de voorwaardelijke operator de op een na laagste prioriteit heeft, boven de toewijzingsoperators , is er zelden behoefte aan haakjes rondom de voorwaarde , maar haakjes is vereist rond de hele constructie van de voorwaardelijke operator in combinatie met andere operators:

// no parenthesis needed for expressions in the 3 parts
10 <= a && a < 19 ? b * 5 : b * 7

// parenthesis required
7 * (a > 0 ? 2 : 5)

Voorwaardelijke operators nesten kan ook worden gedaan in het derde deel, waar het meer werkt als ketenen of als een schakeloptie.

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))

Voetnoot:

1 - Zowel de Java Language Specification als de Java Tutorial noemen de ( ? : :) Operator de Conditional Operator . De tutorial zegt dat het "ook bekend staat als de Ternary Operator" omdat het (momenteel) de enige ternaire operator is die wordt gedefinieerd door Java. De terminologie "Voorwaardelijke operator" is consistent met C en C ++ en andere talen met een vergelijkbare operator.

De bitsgewijze en logische operatoren (~, &, |, ^)

De Java-taal biedt 4 operatoren die bitgewijze of logische bewerkingen uitvoeren op gehele of booleaanse operanden.

  • De complement ( ~ ) operator is een unaire operator die een bitgewijze of logische inversie van de bits van één operand uitvoert; zie JLS 15.15.5. .
  • De operator AND ( & ) is een binaire operator die een bitwise of logische "en" van twee operanden uitvoert; zie JLS 15.22.2. .
  • De operator OR ( | ) is een binaire operator die een bitwise of logische "inclusief of" van twee operanden uitvoert; zie JLS 15.22.2. .
  • De XOR ( ^ ) -operator is een binaire operator die een bitwise of logische "exclusief of" van twee operanden uitvoert; zie JLS 15.22.2. .

De logische bewerkingen die door deze operatoren worden uitgevoerd wanneer de operanden Booleans zijn, kunnen als volgt worden samengevat:

EEN 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

Merk op dat voor integer operanden de bovenstaande tabel beschrijft wat er gebeurt voor individuele bits. De operatoren werken feitelijk op alle 32 of 64 bits van de operand of operanden parallel.

Operandtypen en resultatietypen.

De gebruikelijke rekenkundige conversies zijn van toepassing wanneer de operanden gehele getallen zijn. Veel voorkomende use-cases voor de bitsgewijze operatoren


De operator ~ wordt gebruikt om een Booleaanse waarde om te keren of alle bits in een geheel getal-operand te wijzigen.

De operator & wordt gebruikt voor het "maskeren" van enkele bits in een integer operand. Bijvoorbeeld:

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

De | operator wordt gebruikt om de waarheidswaarden van twee operanden te combineren. Bijvoorbeeld:

int word2 = 0b01011111; 
// Combine the bottom 2 bits of word1 with the top 30 bits of word2
int combined = (word & mask) | (word2 & ~mask);   // -> 0b01011110

De operator ^ wordt gebruikt voor het schakelen of "omdraaien" van bits:

int word3 = 0b00101010;
int word4 = word3 ^ mask;             // -> 0b00101001

Voor meer voorbeelden van het gebruik van de logische operatoren op, zie Bit Manipulatie

Het exemplaar van exploitant

Deze operator controleert of het object van een bepaald type klasse / interface is. instanceof- operator is geschreven als:

( Object reference variable ) instanceof  (class/interface type)

Voorbeeld:

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 );
   }
}

Dit zou het volgende resultaat opleveren:

true

Deze operator retourneert nog steeds true als het object dat wordt vergeleken, de toewijzing is die compatibel is met het type aan de rechterkant.

Voorbeeld:

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 );
   }
}

Dit zou het volgende resultaat opleveren:

true

De toewijzingsoperators (=, + =, - =, * =, / =,% =, << =, >> =, >>> =, & =, | = en ^ =)

De linkerhandoperand voor deze operatoren moet een niet-definitieve variabele of een element van een array zijn. De rechterhand-operand moet toewijsbaar zijn met de linkerhand-operand. Dit betekent dat de typen hetzelfde moeten zijn of het rechter operandtype converteerbaar moet zijn naar het linker operandentype door een combinatie van boksen, unboxing of verbreding. (Voor volledige details raadpleegt u JLS 5.2 .)

De precieze betekenis van de operatoren "bedienen en toewijzen" wordt door JLS 15.26.2 gespecificeerd als:

Een samengestelde toewijzingsuitdrukking in de vorm E1 op= E2 is equivalent aan E1 = (T) ((E1) op (E2)) , waarbij T het type E1 , behalve dat E1 slechts eenmaal wordt geëvalueerd.

Merk op dat er een impliciete typecast is vóór de definitieve toewijzing.

1. =

De eenvoudige toewijzingsoperator: wijst de waarde van de rechterhandoperand toe aan de linkerhandoperand.

Voorbeeld: c = a + b voegt de waarde van a + b aan de waarde van c en wijst deze toe aan c

2. +=

De operator "toevoegen en toewijzen": voegt de waarde van de rechterhand-operand toe aan de waarde van de linkerhand-operand en wijst het resultaat toe aan de linkerhand-operand. Als de linkerhandoperand het type String , is dit een operator "samenvoegen en toewijzen".

Voorbeeld: c += a is ongeveer hetzelfde als c = c + a

3. -=

De operator "aftrekken en toewijzen": trekt de waarde van de rechteroperand af van de waarde van de linkeroperand en wijst het resultaat toe aan de linkeroperand.

Voorbeeld: c -= a is ongeveer hetzelfde als c = c - a

4. *=

De operator "vermenigvuldigen en toewijzen": vermenigvuldigt de waarde van de rechterhand-operand met de waarde van de linkerhand-operand en wijst het resultaat toe aan de linkerhand-operand. .

Voorbeeld: c *= a is ongeveer hetzelfde als c = c * a

5. /=

De operator "delen en toewijzen": deelt de waarde van de rechterhand-operand door de waarde van de linkerhand-operand en wijst het resultaat toe aan de linkerhand-operand.

Voorbeeld: c /*= a is ongeveer hetzelfde als c = c / a

6. %=

De operator "modulus en toewijzen": berekent de modulus van de waarde van de rechterhand-operand door de waarde van de linkerhand-operand en wijst het resultaat toe aan de linkerhand-operand.

Voorbeeld: c %*= a is ongeveer hetzelfde als c = c % a

7. <<=

De operator "naar links verplaatsen en toewijzen".

Voorbeeld: c <<= 2 is ongeveer hetzelfde als c = c << 2

8. >>=

De operator "rekenkundig naar rechts verplaatsen en toewijzen".

Voorbeeld: c >>= 2 is ongeveer hetzelfde als c = c >> 2

9. >>>=

De operator "Logisch rechts verschuiven en toewijzen".

Voorbeeld: c >>>= 2 is ongeveer hetzelfde als c = c >>> 2

10. &=

De operator "bitsgewijs en toewijzen".

Voorbeeld: c &= 2 is ongeveer hetzelfde als c = c & 2

11. |=

De operator "bitsgewijs of en toewijzen".

Voorbeeld: c |= 2 is ongeveer hetzelfde als c = c | 2

12. ^=

De operator "bitsgewijs exclusief of en toewijzen".

Voorbeeld: c ^= 2 is ongeveer hetzelfde als c = c ^ 2

De voorwaardelijke en voorwaardelijke of exploitanten (&& en ||)

Java biedt een voorwaardelijke en een voorwaardelijke of operator, die beide een of twee operanden van het type boolean en een boolean resultaat produceren. Dit zijn:

  • && - de voorwaardelijke AND-operator,

  • || - de voorwaardelijke OF-operatoren. De evaluatie van <left-expr> && <right-expr> is gelijk aan de volgende pseudo-code:

    {
       boolean L = evaluate(<left-expr>);
       if (L) {
           return evaluate(<right-expr>);
       } else {
           // short-circuit the evaluation of the 2nd operand expression
           return false;
       }
    }
    

De evaluatie van <left-expr> || <right-expr> is gelijk aan de volgende pseudo-code:

    {
       boolean L = evaluate(<left-expr>);
       if (!L) {
           return evaluate(<right-expr>);
       } else {
           // short-circuit the evaluation of the 2nd operand expression
           return true;
       }
    }

Zoals de pseudocode hierboven illustreert, is het gedrag van de kortsluitexploitanten gelijk aan het gebruik van if / else verklaringen.

Voorbeeld - && gebruiken als bewaker in een uitdrukking

Het volgende voorbeeld toont het meest voorkomende gebruikspatroon voor de operator && . Vergelijk deze twee versies van een methode om te testen of een opgegeven geheel Integer nul is.

public boolean isZero(Integer value) {
    return value == 0;
}

public boolean isZero(Integer value) {
    return value != null && value == 0;
}

De eerste versie werkt in de meeste gevallen, maar als de value argument null , dan is een NullPointerException zal worden geworpen.

In de tweede versie hebben we een "bewakingstest" toegevoegd. De value != null && value == 0 expressie wordt geëvalueerd door eerst de value != null test uit te voeren. Als de null -test slaagt (dwz evalueert true ) dan de value == 0 wordt expressie geëvalueerd. Als de null mislukt, wordt de evaluatie van value == 0 overgeslagen (kortgesloten) en krijgen we geen NullPointerException .

Voorbeeld - met && om een kostbare berekening te voorkomen

Het volgende voorbeeld laat zien hoe && kan worden gebruikt om een relatief dure berekening te voorkomen:

public boolean verify(int value, boolean needPrime) {
    return !needPrime | isPrime(value);
}

public boolean verify(int value, boolean needPrime) {
    return !needPrime || isPrime(value);
}

In de eerste versie, beide operanden van de | wordt altijd geëvalueerd, dus de (dure) isPrime methode wordt onnodig aangeroepen. De tweede versie voorkomt onnodig bellen met || in plaats van | .

The Shift Operators (<<, >> en >>>)

De Java-taal biedt drie operatoren voor het bitgewijs schakelen op 32 en 64 bit gehele waarden. Dit zijn allemaal binaire operatoren waarbij de eerste operand de te verschuiven waarde is en de tweede operand aangeeft hoe ver te verschuiven.

  • De << of linker shift- operator verschuift de waarde gegeven door de eerste operand naar links met het aantal bitposities gegeven door de tweede operand. De lege posities aan de rechterkant worden gevuld met nullen.

  • De operator '>>' of rekenkundige verplaatsing verschuift de waarde die door de eerste operand wordt gegeven naar rechts met het aantal bitposities dat door de tweede operand wordt gegeven. De lege posities aan de linkerkant worden gevuld door het meest linkse bit te kopiëren. Dit proces staat bekend als tekenextensie .

  • De '>>>' of logische operator voor rechts verschuiven verschuift de waarde die door de eerste operand wordt gegeven naar rechts met het aantal bitposities dat door de tweede operand wordt gegeven. De lege posities aan de linkerkant worden gevuld met nullen.

Opmerkingen:

  1. Deze operatoren vereisen een int of long waarde als de eerste operand en produceren een waarde met hetzelfde type als de eerste operand. (U moet een expliciete typecast gebruiken wanneer u het resultaat van een verschuiving toewijst aan een byte , short of char variabele.)

  2. Als u een shift-operator gebruikt met een eerste operand die een byte , char of short , wordt deze gepromoveerd tot een int en produceert de bewerking een int .)

  3. De tweede operand wordt gereduceerd modulo het aantal bits van de bewerking om het bedrag van de verschuiving te geven. Zie Modulus-voorbeelden voor meer informatie over het wiskundige mod-concept .

  4. De bits die door de bewerking van het linker- of rechteruiteinde zijn verschoven, worden verwijderd. (Java biedt geen primitieve "roteren" -operator.)

  5. De rekenkundige shift-operator is equivalent door een (twee-complement) getal te delen door een macht van 2.

  6. De linker shift-operator is equivalent door een (twee-complement) getal te vermenigvuldigen met een macht van 2.

De volgende tabel helpt u de effecten van de drie ploegendiensten te zien. (De cijfers zijn uitgedrukt in binaire notatie om de visualisatie te vergemakkelijken.)

operand1 operand2 << >> >>>
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

Er voorbeelden van de gebruiker van shift-operators bij bitmanipulatie

De Lambda-operator (->)

Vanaf Java 8 is de Lambda-operator ( -> ) de operator die wordt gebruikt om een Lambda-expressie te introduceren. Er zijn twee veel voorkomende syntaxis, zoals geïllustreerd door deze voorbeelden:

Java SE 8
  a -> a + 1              // a lambda that adds one to its argument
  a -> { return a + 1; }  // an equivalent lambda using a block.

Een lambda-expressie definieert een anonieme functie, of juister een instantie van een anonieme klasse die een functionele interface implementeert.

(Dit voorbeeld is hier opgenomen voor de volledigheid. Raadpleeg het onderwerp Lambda-uitdrukkingen voor de volledige behandeling.)

De relationele operatoren (<, <=,>,> =)

De operatoren < , <= , > en >= zijn binaire operatoren voor het vergelijken van numerieke typen. De betekenis van de operators is zoals je zou verwachten. Als a en b worden gedeclareerd als byte , short , char , int , long , float , double of de overeenkomstige boxtypes:

- `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`. 

Het resultaattype voor deze operators is in alle gevallen boolean .

Relationele operatoren kunnen worden gebruikt om getallen met verschillende typen te vergelijken. Bijvoorbeeld:

int i = 1;
long l = 2;
if (i < l) {
    System.out.println("i is smaller");
}

Relationele operatoren kunnen worden gebruikt wanneer een of beide getallen voorbeelden zijn van numerieke typen in een vak. Bijvoorbeeld:

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");
}

Het precieze gedrag is als volgt samengevat:

  1. Als een van de operanden van het type boxed is, wordt het unboxed.
  2. Als een van de operanden nu een byte , short of char , wordt deze gepromoveerd tot een int .
  3. Als de typen operanden niet hetzelfde zijn, wordt de operand met het "kleinere" type bevorderd tot het "grotere" type.
  4. De vergelijking wordt uitgevoerd op de resulterende int , long , float of double waarden.

Je moet voorzichtig zijn met relationele vergelijkingen waarbij zwevende kommagetallen betrokken zijn:

  • Uitdrukkingen die drijvende-kommagetallen berekenen, vertonen vaak afrondingsfouten vanwege het feit dat de representaties van de drijvende komma van de computer een beperkte precisie hebben.
  • Bij het vergelijken van een geheel getaltype en een drijvend punttype, kan de conversie van het gehele getal naar een drijvend punt ook leiden tot afrondingsfouten.

Ten slotte ondersteunt Java bit het gebruik van relationele operatoren met alle andere typen dan hierboven vermeld. U kunt deze operatoren bijvoorbeeld niet gebruiken om tekenreeksen, reeksen getallen, enzovoort te vergelijken.



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow