4. Operátorok

Az operátorok egy, kettő vagy három operanduson hajtanak végre egy műveletet. Az egyoperandusú operátorokat unáris operátoroknak hívjuk. Például a ++ operátor az operandusát 1-el növeli. A kétoperandusú operátorokat bináris operátoroknak hívjuk. Például az = operátor a jobb oldali operandus értékét a baloldali operandusba másolja. Végül a háromoperandusú operátor három operandust vár. Javában egy háromoperandusú operátor van, a ? : feltételes operátor.

Az unáris operátorok lehetővé teszik a prefix és postfix jelölés is:

operator op             //prefix
op operator             //postfix

Az összes bináris operátor infix jelölést alkalmaz, vagyis az operátor az operandusok között szerepel:

op1 operator op2        //infix

A háromoperandusú operátor szintén infix jelölést tesz lehetővé. Az operátor mindkét komponense az operandusok között szerepel:

op1 ? op2 : op3         //infix

A művelet végrehajtása után a kifejezés értéke rendelkezésre áll. Az érték függ az operátortól és az operandusok típusától is. Aritmetikai operátorok esetén a típus alá van rendelve az operandusoknak: ha két int értéket adunk össze, az érték is int lesz.

Megjegyzendő, hogy a Javában a kifejezések kiértékelési sorrendje rögzített, vagyis egy művelet operandusai mindig balról jobbra értékelődnek ki (ha egyáltalán kiértékelődnek, lásd rövidzár kiértékelés), még a művelet elvégzése előtt.

4.1. Aritmetikai operátorok

A Java programozási nyelvben sokféle aritmetikai operátor áll rendelkezésre lebegőpontos és egész számokhoz. Ezek az operátorok a + (összeadás), - (kivonás), * (szorzás), / (osztás) és % (maradékképzés). A következő lista összefoglalja a Java nyelv kétoperandusú aritmetikai operátorait.

  • op1 + op2 op1 és op2 összeadása, valamint sztring összefűzés
  • op1 - op2 op2 és op1 különbsége
  • op1 * op2 op1 és op2 szorzata
  • op1 / op2 op1 és op2 (egész) hányadosa
  • op1 % op2 op1 és op2 egész osztás maradéka

Az ArithmeticDemo példaprogram definiál két egész és két dupla-pontosságú lebegőpontos számot, és öt aritmetikai operátort mutat be. Ezen kívül használja a + operátort sztringek összefűzésére.

public class ArithmeticDemo {
    public static void main(String[] args) {
        int i = 37;
        int j = 42;
        double x = 27.475;
        double y = 7.22;
        System.out.println("Variable values...");
        System.out.println("    i = " + i);
        System.out.println("    j = " + j);
        System.out.println("    x = " + x);
        System.out.println("    y = " + y);
        System.out.println("Adding...");
        System.out.println("    i + j = " + (i + j));
        System.out.println("    x + y = " + (x + y));
        System.out.println("Subtracting...");
        System.out.println("    i - j = " + (i - j));
        System.out.println("    x - y = " + (x – y));
        System.out.println("Multiplying...");
        System.out.println("    i * j = " + (i * j));
        System.out.println("    x * y = " + (x * y));
        System.out.println("Dividing...");
        System.out.println("    i / j = " + (i / j));
        System.out.println("    x / y = " + (x / y));
        System.out.println("Computing the remainder...");
        System.out.println("    i % j = " + (i % j));
        System.out.println("    x % y = " + (x % y));
        System.out.println("Mixing types...");
        System.out.println("    j + y = " + (j + y));
        System.out.println("    i * x = " + (i * x));
    }
}

A program kimenete:

Variable values...
    i = 37
    j = 42
    x = 27.475
    y = 7.22
Adding...
    i + j = 79
    x + y = 34.695
Subtracting...
    i - j = -5
    x - y = 20.255
Multiplying...
    i * j = 1554
    x * y = 198.37
Dividing...
    i / j = 0
    x / y = 3.8054
Computing the remainder...
    i % j = 37
    x % y = 5.815
Mixing types...
    j + y = 49.22
    i * x = 1016.58

4.1.1 Implicit konverzió

Amikor egy aritmetikai operátor egyik operandusa egész, a másik pedig lebegőpontos, akkor az eredmény is lebegőpontos lesz. Az egész érték implicit módon lebegőpontos számmá konvertálódik, mielőtt a művelet végrehajtódna. A következő lista összefoglalja az aritmetikai operátorok értékét az adattípusok függvényében. A szükséges konverziók még a művelet végrehajtása előtt végre fognak hajtódni.

  • long az egyik operandus sem lebegőpontos, és legalább az egyik long
  • int az egyik operandus sem lebegőpontos, és nem long
  • double legalább az egyik operandus double
  • float legalább az egyik operandus float, és a másik nem double

A + és - operátorok unáris (egyoperandusú) operátorokként is használhatók:

  • +op int értékké konvertálja a byte, short és char értéket
  • -op aritmetikai negálás

A ++ operátor növeli az operandus értékét, a -- pedig csökkenti eggyel. Mindkettőt írhatjuk az operandus elé (prefix) és után (postfix) is. A prefix forma esetén először történik az érték növelése vagy csökkentése, majd a kifejezés értéke is a megváltozott érték lesz. A postfix használat esetén fordítva történik a végrehajtás: először értékelődik ki az operandus, majd utána hajtódik végre a ++ vagy -- művelet.

A következő SortDemo program mindkét operátort használja:

public class SortDemo {
    public static void main(String[] args) {
        int[] arrayOfInts = { 32, 87, 3, 589, 12, 1076, 2000, 8, 622, 127 };
        for (int i = arrayOfInts.length; --i >= 0; ) {
            for (int j = 0; j < i; j++) {
                if (arrayOfInts[j] > arrayOfInts[j+1]) {
                    int temp = arrayOfInts[j];
                    arrayOfInts[j] = arrayOfInts[j+1];
                    arrayOfInts[j+1] = temp;
                 }
             }
         }
         for (int i = 0; i < arrayOfInts.length; i++) {
             System.out.print(arrayOfInts[i] + " ");
         }
         System.out.println();
    }
}

A program a rendezett számsorozatot fogja megjeleníteni.

4.2. Relációs operátorok

A relációs operátorok összehasonlítanak két értéket, és meghatározzák a köztük lévő kapcsolatot. Például a != true-t ad, ha a két operandus nem egyenlő. A következő táblázatban összegyűjtöttük a relációs operátorokat:

  • op1 > op2 true-t ad vissza, ha op1 nagyobb, mint op2
  • op1 >= op2 true-t ad vissza, ha op1 nagyobb vagy egyenlő, mint op2
  • op1 < op2 true-t ad vissza, ha op1 kisebb, mint op2
  • op1 <= op2 true-t ad vissza, ha op1 kisebb vagy egyenlő, mint op2
  • op1 == op2 true-t ad vissza, ha op1 és op2 egyenlők
  • op1 != op2 true-t ad vissza, ha op1 és op2 nem egyenlők

A következő példában (RelationalDemo) definiálunk három int típusú számot, és relációs operátorok használatával összehasonlítjuk őket. Az összehasonlító műveleteket félkövér betűtípussal emeltük ki:

public class RelationalDemo {
    public static void main(String[] args) {
        int i = 37;
        int j = 42;
        int k = 42;
        System.out.println("Variable values...");
        System.out.println("    i = " + i);
        System.out.println("    j = " + j);
        System.out.println("    k = " + k);
        System.out.println("Greater than...");
        System.out.println("    i > j = " + (i > j));//false
        System.out.println("    j > i = " + (j > i));//true
        System.out.println("    k > j = " + (k > j));//false;
        System.out.println("Greater than or equal to...");
        System.out.println("    i >= j = " + (i >= j));//false
        System.out.println("    j >= i = " + (j >= i));//true
        System.out.println("    k >= j = " + (k >= j));//true
        System.out.println("Less than...");
        System.out.println("    i < j = " + (i < j));//true
        System.out.println("    j < i = " + (j < i));//false
        System.out.println("    k < j = " + (k < j));//false
        System.out.println("Less than or equal to...");
        System.out.println("    i <= j = " + (i <= j));//true
        System.out.println("    j <= i = " + (j <= i));//false
        System.out.println("    k <= j = " + (k <= j));//true
        System.out.println("Equal to...");
        System.out.println("    i == j = " + (i == j));//false
        System.out.println("    k == j = " + (k == j));//true
        System.out.println("Not equal to...");
        System.out.println("    i != j = " + (i != j));//true
        System.out.println("    k != j = " + (k != j));//false
    }
}

A fenti program kimenete:

Variable values...
    i = 37
    j = 42
    k = 42
Greater than...
    i > j = false
    j > i = true
    k > j = false
Greater than or equal to...
    i >= j = false
    j >= i = true
    k >= j = true
Less than...
    i < j = true
    j < i = false
    k < j = false
Less than or equal to...
    i <= j = true
    j <= i = false
    k <= j = true
Equal to...
    i == j = false
    k == j = true
Not equal to...
    i != j = true
    k != j = false

4.3. Logikai operátorok

A relációs operátorokat gyakran használják logikai operátorokkal együtt, így összetettebb logikai kifejezéseket hozhatunk létre. A Java programozási nyelv hatféle logikai operátort – öt bináris és egy unáris – támogat, ahogy azt a következő táblázat mutatja:

  • op1 && op2 Logikai és: true-t ad vissza, ha op1 és op2 egyaránt true; op2 feltételes kiértékelésű
  • op1 || op2 Logikai vagy: true-t ad vissza, ha op1 vagy op2 true; op2 feltételes kiértékelésű
  • !op Logikai nem: true-t ad vissza, ha op false, és fordítva
  • op1 & op2 Bitenkénti és: true-t ad vissza, ha op1 és op2 egyaránt boolean és true; op1 és op2 mindig kiértékelődik; ha mindkét operandus szám, akkor bitenkénti és művelet
  • op1 | op2 Bitenkénti vagy: true-t ad vissza, ha op1 és op2 egyaránt boolean vagy op1 vagy op2 true; op1 és op2 mindig kiértékelődik; ha mindkét operandus szám, akkor bitenkénti vagy művelet
  • op1 ^ op2 Bitenkénti kizáró vagy: true-t ad vissza, ha op1 és op2 különböző — vagy egyik, vagy másik, de nem egyszerre mindkét operandus true

A következő példa az && operátort használja a két rész-kifejezés logikai értékének összekapcsolására:

0 <= index && index < NUM_ENTRIES

4.3.1 Rövidzár kiértékelés

Bizonyos esetekben a logikai operátor második operandusa nem értékelődik ki. Például a következő esetben:

(numChars < LIMIT) && (...)

Az && operátor csak akkor ad vissza true-t, ha mindkét operandus true. Tehát, ha numChars nagyobb vagy egyenlő, mint LIMIT, akkor && bal oldala false, és a kifejezés visszaadott eredménye a jobb oldali operandus kiértékelése nélkül születik meg. Ilyen esetekben a fordító nem értékeli ki a jobb oldali operandust. Ilyenkor a jobb oldali kifejezés miatt közvetett mellékhatások léphetnek fel, például ha adatfolyamból olvasunk, értékeket aktualizálunk, vagy számításokat végzünk a jobb oldali operandusban. Ehhez hasonlóan, ha a || operátor bal oldali operandusa igaz, felesleges a jobboldalt kiértékelni, nem is fog megtörténni.

Ha mindkét operandus logikai, az & operátor hasonlóan viselkedik, mint az &&. Azonban & mindig kiértékelődik és true-t ad vissza, ha mindkét operandusa true. Ha az operandusok boolean-típusúak, | azonos műveletet végez, mint ||.

A fenti működés miatt nem érdemes olyan kódot készíteni, amelyik a jobboldali operandusának kiértékelése során a kiértékelésen túl mást is tesz. Például veszélyes, nehezen áttekinthető lesz a következő feltételes kifejezés:

if (a < b && b++ < f(c) ) {...}

Ha a bal oldali operandus (a<b) hamis, akkor sem a ++ operátor, sem az f függvényhívás nem fog végrehajtódni.

4.4. Bitléptető és bitenkénti logikai operátorok

A léptető operátorok bit műveleteket végeznek, a kifejezés első operandusának bitjeit jobbra, vagy balra léptetik. A következő táblázat a Java nyelvben használt léptető operátorokat mutatja be:

  • op1 << op2 op1 bitjeit op2 értékével balra lépteti; jobbról nullákkal tölti fel
  • op1 >> op2 op1 bitjeit op2 értékével jobbra lépteti; balról a legnagyobb helyértékű bitet tölt fel
  • op1 >>> op2 op1 bitjeit op2 értékével jobbra lépteti; balról nullákkal tölt fel.

Mindegyik operátor az első operandus bitjeit lépteti az operátor által megadott irányba a második operandus értékével. Például a következő kifejezésben a 13-as egész szám bitjeit léptetjük 1-el jobbra:

13 >> 1;

A 13-as szám kettes számrendszerbeli értéke: 1101. A léptetés eredménye: 1101 egy pozícióval jobbra - 110, (decimálisan 6). A bal oldali biteket 0-val töltöttük fel.

A következő táblázatban a Java programozási nyelvben használatos bitenkénti logikai operátorokat és funkciójukat láthatjuk:

  • op1 & op2 Bitenkénti és, ha mindkét operandus szám; feltételes és ha mindkét operandus logikai
  • op1 | op2 Bitenkénti vagy, ha mindkét operandus szám; feltételes vagy, ha mindkét operandus logikai
  • op1 ^ op2 Bitenkénti kizáró vagy (xor)
  • ~op2 Bitenkénti negáció

És

Ha az operandus szám, az & operátor bitenkénti és műveletet hajt végre páronként (helyérték szerint) az operandus bitjein. Az és művelet akkor ad vissza 1-et, ha a kifejezés mindkét bitje 1.

Ha az és műveletet két decimális számon hajtjuk végre, például a 12-n és 13-n (12&13) akkor az adott számok kettes számrendszerbeli alakján bitenként kell végrehajtanunk az és műveletet. Az eredmény így 12 lesz decimálisan.

Ha mindkét operandus 1, az és művelet eredményként is 1-et ad. Ellenkező esetben 0-t.

Vagy

Ha mindkét operandus szám, akkor a | operátor a vagy műveletet hajtja végre. A vagy művelet 1-et ad eredményül, ha két bit közül bármelyik értéke 1.

Kizáró vagy

Ha mindkét operandus szám, akkor a ^ operátor a kizáró vagy (xor) műveletet hajtja végre. Kizáró vagy esetén a kifejezés eredménye akkor egy, ha a két operandus bit különböző, ellenkező esetben az eredmény 0.

Negáció

Végül a negációs operátor (~) az operandus bitjeit egyenként az ellenkezőjére fordítja: ha az operandus bitje 1, akkor az eredmény 0, ha az operandus bitje 0, akkor az eredmény 1. Például: ~1011 (11) = 0100 (4).

4.4.1 Bitmanipulációk a gyakorlatban

Egyebek között a bitenkénti műveletekkel hasznosan kezelhetők a logikai bitek is. Tegyük fel például, hogy az adott programban vannak logikai bitek, melyek a különböző összetevők állapotát határozzák meg a programban. Ez célravezetőbb, mint különböző boolean változók definiálása. Bitmanipuláció segítségével beállíthatók, és változtathatók az adott bitek értékei.

Először definiáljunk konstansokat, melyek a program különböző bitjeit határozzák majd meg. Ezek a konstansok a kettes számrendszer különböző helyi értékei, így biztosíthatjuk, hogy később nem lesznek összekeverhetők. Később ezek a konstansok a bit változók értékeit segítik majd kinyerni. A következő példában a biteket 0 értékűnek inicializáljuk, ami azt jelenti, hogy minden érték hamis.

static final int VISIBLE = 1;
static final int DRAGGABLE = 2;
static final int SELECTABLE = 4;
static final int EDITABLE = 8;

int flags = 0;

A VISIBLE szimbolikus konstans jelzi, ha valami láthatóvá válik a programban. Ezt a bitet állítja egyesre a következő sor:

flags = flags | VISIBLE;

A láthatóságot a következő képen tesztelhetjük:

if ((flags & VISIBLE) == VISIBLE) {
    ...
}

Itt látható a teljes program (BitwiseDemo), mely magában foglalja a fenti kódot:

public class BitwiseDemo {
    static final int VISIBLE = 1;
    static final int DRAGGABLE = 2;
    static final int SELECTABLE = 4;
    static final int EDITABLE = 8;
    public static void main(String[] args) {
        int flags = 0;
        flags = flags | VISIBLE;
        flags = flags | DRAGGABLE;
        if ((flags & VISIBLE) == VISIBLE) {
            if ((flags & DRAGGABLE) == DRAGGABLE) {
                 System.out.println("Flags are Visible " + "and Draggable.");
            }
        }
        flags = flags | EDITABLE;
        if ((flags & EDITABLE) == EDITABLE) {
           System.out.println("Flags are now also Editable.");
        }
    }
}

A fenti program kimenete:

Flags are Visible and Draggable.
Flags are now also Editable.

4.5. Értékadó operátorok

Az alap értékadó (=) operátort használhatjuk arra, hogy egy értéket hozzárendeljünk egy változóhoz. A MaxVariablesDemo program az =-t használja, hogy inicializálja a változóit:

byte largestByte = Byte.MAX_VALUE;
short largestShort = Short.MAX_VALUE;
int largestInteger = Integer.MAX_VALUE;
long largestLong = Long.MAX_VALUE;
float largestFloat = Float.MAX_VALUE;
double largestDouble = Double.MAX_VALUE;
char aChar = 'S';
boolean aBoolean = true;

A Java programozási nyelv azt is megengedi a rövidített értékadó operátorok segítségével, hogy aritmetikai, értéknövelési, valamint bitenkénti műveletvégzést összekössük az értékadással.

Például, ha egy változó értékét akarjuk növelni, akkor:

i=i+2;

Ezt le lehet rövidíteni a += rövidített operátor segítségével:

i += 2;

A fenti két értékadás megegyezik.

A használható operátorok:

  • -=
  • *=
  • /=
  • %=
  • &=
  • |=
  • ^=
  • <<=
  • >>=
  • >>>=

4.6. Egyéb operátorok

A Java nyelv támogatja még a következő táblázatban foglalt operátorokat.

  • ?: Feltételes operátor
  • [] Tömbök deklarálására, létrehozására és elemeinek hozzáférésére használt operátor.
  • . Minősített hivatkozás
  • ( params ) Vesszővel elválasztott paramétereket foglalja keretbe.
  • ( type ) Átkonvertálja az értéket egy meghatározott típussá.
  • new Új objektum létrehozása.
  • instanceof Megállapítja, hogy az első operandus típusa-e a második operandus.

4.7. Ellenőrző kérdések

  • Mit jelent a logikai kifejezés?
  • Hogyan kell logikai típusú változókat deklarálni?
  • Mire használható a != operátor?
  • Mire használható a || operátor?
  • Az és és vagy operátorok jobb oldali operandusa mikor kerül kiértékelésre?
  • Mi a különbség a >> és >>> operátorok között?

Mit ír ki a következő kódrészlet?

System.out.println(4/3);

  • 6
  • 0
  • 1
  • 7