29 czerwca 2008

SCJP – Operatory

Ledwie zdążyłem wyrazić swą radość – w artykule "SCJP - Odśmiecacz, czyli mechanizm przywracania pamięci" – z powodu zakończenia przerabiania trzeciego rozdziału Książki, a tymczasem już kończymy rozdział czwarty. Zgadza się! Cały rozdział czwarty streszczony w jednym, dzisiejszym artykule. A będzie dziś o operatorach wszelkiej maści.

Operatory przypisania opisałem zasadniczo w artykule "SCJP - Operatory przypisania dla typów prymitywnych". Na egzaminie, oprócz zwykłego operatora przypisania ‘=’ występują podobno jeszcze tylko operatory ‘+=’, ‘-=’, ‘*=’ oraz ‘/=’. Jedyną rzeczą, jaką można w tym kontekście dodać jest, że prawa strona wyrażeń z operatorami przypisania jest zawsze wyliczana jako pierwsza, tak więc wyrażenie ‘x *= 1 + 2’ jest równoważne wyrażeniu ‘x = x * (1 + 2)’ a nie ‘x = x * 1 + 2’.

Operatory arytmetyczne, mogące pojawić się na egzaminie SCJP to ‘+’, ‘-‘, ‘*’, ‘/’ i ‘%’ czyli reszta z dzielenia oraz operatory inkrementacji i dekrementacji ‘++’ oraz ‘--‘. Na komentarz zasługuje operator ‘+’. Oprócz tego, że jest on operatorem dodawania, może także być stosowany jako operator konkatenacji String’ów. Pamiętajmy, że jeśli choć jeden z operandów jest String’iem, to ‘+’ nie jest operatorem dodawania, tylko operatorem konkatenacji. Pamiętajmy także o kolejności wykonywania działań. Dla przykładu, instrukcja

System.out.println("2 plus 2 to " + 2 + 2);

powoduje wyświetlenie napisu "2 plus 2 to 22". Ale już instrukcja

System.out.println("2 razy 2 to " + 2 * 2);

daje wynik oczekiwany, tj. "2 razy 2 to 4".

Pierwszeństwo mają zawsze operatory unarne, a więc ‘++’ i ‘--‘. Następnie wykonywane są operacje ‘*’, ‘/’ oraz ‘%’ a operatory ‘+’ i ‘-‘ wiążą najsłabiej. Poza tym, jeśli kolejność wykonywania działań nie jest w pełni wyznaczona przez pierwszeństwo operatorów to są one wykonywane od lewej do prawej. W wyrażeniu >>"2 plus 2 to " + 2 + 2<< jako pierwsza wykona się więc operacja konkatenacji >>"2 plus 2 to " + 2<< której wynikiem jest "2 plus 2 to 2". Następnie, wykonana będzie konkatenacja >>"2 plus 2 to 2" + 2<< a więc w rezultacie otrzymamy napis "2 plus 2 to 22". Ponieważ jednak operator ‘*’ wiąże silniej niż ‘+’, w wyrażeniu >>"2 razy 2 to " + 2 * 2<< w pierwszej kolejności zostanie wyliczona wartość dla >>2 * 2<<, a potem wykonana będzie konkatenacja >>"2 razy 2 to " + 4<<.

Na SCJP pojawiają się także operatory logiczne. Są to ‘&’, ‘|’ i ‘^’ – które są operacjami logicznymi dla operandów typu logicznego a operacjami bitowymi dla operandów typu całkowitoliczbowego – oraz ‘&&’, ‘||’ i ‘!’. Różnica między operatorami ‘&’ i ‘|’ oraz ‘&&’ i ‘||’ zastosowanymi do operandów typu logicznego jest taka, że te pierwsze wyliczają wartość wyrażeń logicznych zachłannie a te drugie leniwie.

Operatory relacyjne ‘<’, ‘<=’, ‘>’, ‘>=’ mogą być stosowane tylko do porównywania wartości typów numerycznych i typu ‘char’, przy czym za wartość dla typu ‘char’ przyjmuje się kod Unicode znaku. Operatory ‘==’ oraz ‘!=’ można stosować dodatkowo do porównywania wartości typu logicznego i typów referencyjnych.

Operator ‘instanceof’ służy do testowania, czy referencja odnosi się do obiektu danego typu. Referencja jest operandem lewostronnym a nazwa klasy bądź interfejsu prawostronnym. Mówiąc precyzyjniej, wynikiem wyrażenia ‘x instanceof SomeClass’ jest ‘true’ gdy instancja ‘x’ IS-A ‘SomeClass’. Co to oznacza IS-A opisywałem w artykule "SCJP - Związki typu IS-A oraz HAS-A". A co, jeśli ‘x’ ma wartość ‘null’? Czy w rezultacie otrzymamy ‘NullPointerException’? Nie, wyrażenie ‘null instanceof SomeClass’ ma wartość ‘false’ i nic złego się nie dzieje. Trzeba jeszcze zaznaczyć, że operatora ‘instanceof’ nie możemy użyć, jeśli nie ma szans na powodzenie, tj. jeśli typ referencji ‘x’ nie należy do tej samej hierarchii dziedziczenia co klasa ‘SomeClass’. Nie spełnienie tego warunku jest błędem czasu kompilacji. Przykład poniżej.

public class Test {
public static void main(String[] args) {
Integer x = 5;

if(x instanceof Long) // błąd kompilacji!
System.out.println("cuda się zdarzają");
}
}

3 komentarze:

Mariusz Lipiński pisze...

Ciekawy przykład, który daje do myślenia poniżej - efektem uruchomienia programu jest napis "a - b is false".

Pozdr. Mariusz

class Test {
public static void main(String[] args) {
boolean b = condition(false, "a") && condition(true, "b") | condition(true, "c");

System.out.print("- b is " + b);
}

public static boolean condition(boolean returnValue, String descr) {
System.out.print(descr + " ");

return returnValue;
}
}

Łukasz Woźniak pisze...
Ten komentarz został usunięty przez autora.
Łukasz Woźniak pisze...

Hej, dodaje male przypomnienie odnosnie priorytetów operatorów logicznych :

1.& przed |
dlatego tez:
if (true | false & false){} //true

2. ten przypadek pokazuje ze dla || pokusa opuszczenia wyrazenia przedwczesnie jest naprawde silna :)

boolean g = true;
if(true || false && (g=false)) {} //true, bez zmiany g=true

3.&,| przed &&,|| w przypadku gdy kontynuowane jest przetwarzanie
if (false && false | true){} //false

dla porowniania
if (false && false || true){} //true

Pozdr.