Rozdział 2. Operators and assignments

Java Operators

Kolejność operatorów (od największego, do najniższego priorytetu):
  1. Unarne: ++, --, +, -, !, ~, (type)
  2. Arytmetyczne (1): *, /, %
  3. Arytmetyczne (2): +, -
  4. Shift: <<, >>, >>>
  5. Porównania (1): <, <=, >, >=, instanceof
  6. Porównania (2): ==, !=
  7. Bitowe: &, ^, |
  8. Logiczne: &&, ||
  9. Warunkowe: ?:
  10. Przypisania: = op=
Każdy punkt zawiera zbiór operatorów o tym samym priorytecie. Ewaluacja wyrażenia następuje od lewej do prawej, lecz kolejność wykonywania działań zależy od ich priorytetu. Przykład:

int [] a = { 4, 4 };
int b = 1; a[b] = b = 0;

Jako wynik ewaluacji pierwszego członu ostatniego wyrażenia, a[b] wskazywać będzie na ostatni element w tabeli a. Kolejność poszczególnych przypisań wykonywana będzie od prawej do lewej. Zmiennej b przypisana zostanie wartość 0, a następnie ostatniemu elementowi tablicy a aktualna wartość zmiennej b (0).

Maszyna wirtualna Javy przechowuje bitową reprezentację zmiennych w takiej samej postaci na architekturach Little i Big Endian. Operator ~ polega na zamianie wszystkich bitów o wartości 0 na 1, a 1 na 0.

Operatory arytmetyczne

Operatory * i / można stosować dla typów numerycznych oraz char. Zawsze lepiej najpierw mnożyć, a potem dzielić (overflow i underflow - strona 44). Zastosowanie najpierw dzielenia, a następnie mnożenia daje inny wynik, zazwyczaj kompletnie błędny. Dzielenie przez 0 daje ArithmeticException.

Operator modulo

Jeśli drugim argumentem operatora % jest 0, operacja rzuca ArithmeticException. Postępowanie w przypadku operacji modulo jest następujące:
  1. Redukuj wartość pierwszego argumentu o drugi, tak żeby dążyła do 0. W przypadku dodatniej wartości pierwszego argumentu - odejmuj, w przypadku ujemnej - dodawaj.
  2. Jeśli warotść bezwzględna otrzymanej liczby jest mniejsza od wartości drugiego argumentu - jest to wynik. O znaku wyniku decyduje punkt 3.
  3. Wynik jest ujemny jeśli pierwszy argument jest ujemny. Znak drugiego argumentu nie ma znaczenia.
Operator +

Błędny wynik operacji arytmetycznych (overflow i underflow) nie skutkuje żadnym wyjątkiem.
Operator + zastosowany do typów numerycznych daje wynik, który:
1. Jest typem numerycznym.
2. Jest przynajmniej typu int, co wynika z promocji.
3. Jest typu przynajmniej tak dużego jak większy z operandów.
4. Wynik obliczany jest po ówczesnej promocji operandów.

Operator + dla typów nie numerycznych:
1. Przynajmniej jeden z operandów musi być String'iem lub literałem. W przeciwnym wypadku działanie jest nielegalne.
2. Nie String'i konwertowane są do String'u za pomocą metody toString().

Błędy arytmetyczne

Typ numeryczny podzielony lub modulo 0 skutkuje błędem ArithmeticException. Wszystkie porónania z Float lub Double NaN dają fałsz. Należy skorzystać z metody isNaN().

Promocja operandów arytmetycznych

Przed wykonaniem działania operandy uzyskają promocje przynajmniej do typu int.

Operatory logiczne

Podczas porównania mniejszy typ uzyskuje promocje do większego, np. char do float.

Operator Instanceof

Lewy operand może być referencją do obiektu, prawy zaś klasą, interfejsem lub typem tablicowym. Przy typie tablicowym sprawdzane jest czy dana referencja jest tablicą, jak i czy obiekty są prawidłwoego typu, np.:
x instanceof Employee[]
Jeśli lewy operand instanceof jest null, zawsze zwracany jest fałsz.

Inne fakty

1. Na int można robić operacje na bajtach, np. ~
2. Nie można porównywać obiektów różnych typów, np. int ze String.
3. W przypadku operatora ?: także występuje promocja operandów. xxx ? 99.0 : 9 to tak naprawdę xxx ? 99.0 : 9.0

Rozdział 1. Language Fundaments.

Plik źródłowy

Każdy plik źródłowy z rozszerzeniem *.java może zawierać najwyżej jedną definicje klasy publicznej, której nazwa powinna być taka sama jak nazwa pliku. Plik źródłowy składa się z (kolejno) definicji pakietu, importowanych pakietów oraz definicji klas, interfejsów czy obiektów enum. Plik źródłowy musi obowiązkowo znajdować się w strukturze katalogowej odpowiadającej jego pakiecie. Nazwa pakietu składa się tylko ze znaków alfanumerycznych. W przypadku kilku tak samo nazywających się klas, próba użycia w kodzie niejednoznacznej nazwy generuje błąd kompilacji.

Słowa kluczowe

Lista słów zarezerwowanych przez język Java: abstract, assert, boolean, break, byte, case, catch, char, class, const, continue, default, do, double, else, enum, extends, false, final, finally, float, for, goto, if, implements, import, instanceof, int, interface, long, native, new, null, package, private, protected, public, return, short, static, srtictfp, super, switch, synchronized, this, throw, throws, transient, true, try, void, volatile, while.

Nazwa (rozróżniane wielkością liter) musi zaczynać się od litery, dolara ($) lub podkreślenia (_), a potem mogą występować także cyfry. Klasy Float oraz Double zawierają stałe NaN (Not a Number), NEGATIVE_INFINITY oraz POSITIVE_INFINITY. Każde porównanie zawierające NaN zwraca fałsz: http://www.concentric.net/~Ttwang/tech/javafloat.htm.

Literały

Zmiennej typu char można przypisać wartość z klawiatury, lub z systemu Unicode poprzedzony prefixem \u, np. char c = '\u4567';. Zmienne numeryczne mogą być inicjowane w kodzie dziesiętnie, ósemkowo (prefiks 0) oraz szesnastkowo (prefiks 0x, dowolna wielkość x oraz liter). Zwyczajowo zmienna liczbowa jest typu int. Jeśli chcemy użyć long, należy dodać sufiks L lub l. Domyślny typ zmiennoprzecinkowy to double. Aby stosować typ zmiennoprzecinkowy powinien on przyjmować jedną z dostępnych reprezentacji: 1.23, 1.23E+10, 1.23F lub 1.23D (E, F i D mogą być pisane z małej litery).

Tablice

Wszystkie elementy tablicy muszą być tego samego typu (możliwość przechowywania klas pochodnych). Nawiasy mogą występować zarówno przed jak i po nazwie zmiennej tablicowej czy deklaracji argumentu funkcji lub wartości zwracanej. Poniższe deklaracje są poprawne:

  • int tab[];
  • int[] tab;
  • myMethod(int tab[])
  • int myMethod()[]

Podczas tworzenia tablicy, jest ona wypełniana wartościami zerowymi (byte 0, char '\u0000', obiekt null, boolean false). Poprawna inicjalizacja: double tab[] = {0, 9.8, 7d};. Wielowymiarowe tablice mogą mieć różną wielkość. Najbardziej zewnętrzna tablica zawiera jedynie wskaźniki na resztę tablic.

Import

Java 5.0 wprowadza statyczne importowanie (import static). Przykład: import java.awt.Color powoduje konieczność odwołania się przez Color.RED, a import static java.awt.Color.RED umożliwia po prostu RED. Przy statycznym imporcie można używać też '*'. Można importować statyczne metody: import static edu.lantoniak.myMethod(), ale nie podaje się listy argumentów (importowane są wszystkie funkcje o danej nazwie). Import wydłuża czas kompilacji, ale nie ma wpływu na czas ładowania klasy.

Klasy

class Test { int x = 1; public Test() {} } W tym przypadku zmienna 'x' przyjmuje wartość 1 przed uruchomieniem konstruktora. Statyczne zmienne klas inicjalizowane są przy ładowaniu klasy. Każda zmienna automatyczna (nie tablica) musi zostać zainicjowana przed jej użyciem, w innym wypadku otrzymamy błąd kompilacji, np.:

public int zle1() {
int i;
return i+1;
}

public int zle2(int x) {
int res;
if (x == 0) {
res = 1;
}
return res;
}

Domyślna inicjalizacja wykonywana jest w przypadku member variables, class variables i tablic. Zmienne proste przekazywane są "przez wartość". Tablice oraz obiekty przez referencje. Zmiana obiektu referowanego wewnątrz metody wołanej ma skutki na dany obiekt.

Button btn;
btn = new Button("Pink");
replacerBad(btn);
System.out.println(btn.getLabel()); // Pink!
replacerGood(btn);
System.out.println(btn.getLabel()); // Blue!

public void replacerBad(Button replaceMe) {
replaceMe = new Button("Blue");
}

public void replacerGood(Button replaceMe) {
replaceMe.setLabel("Blue");
}

finalize() destruktor klasy. Wszystkie argumenty przekazywane są przez wartość (adres referencji, podwójna referencja). Gdy wartość referencji wynosi null dany obiekt w pamięci widoczny jest dla GC.

SCJP czas zacząć!

Pierwszy dzień nauki do SCJP6. Zbierałem materiały, książki, testy etc. Nie mogę udostępnić owych dobroci, lecz polecam SCJP FAQ na serwisie JavaRanch.