Rozdział 7. Wątki

start() nie powoduje wystartowania wątku, lecz jego dodanie do kolejki gotowych do wykonania. Możliwośći stworzenia wątku:
  1. Implementacja klasy dziedziczącej po Thread.
  2. Implementacja klasy implementującej interface Runnable, stworzenie klasy Thread podając wcześniej zaimplementowaną klasę w konstruktorze.

Raz zakończonego wątku nie można jeszcze raz uruchomić, trzeba go stworzyć na nowo i znowu start(). Ponownie wywołanie start() lub run() spowoduje wywołanie zwyczajnej metody. Wątek można przerwać metodą interrupt().

Nadanie priorytetu nie daje pewności co do natychmiastowego zastosowania zmian. Priorytet wątku mówi o statystycznym ogólnym zasotsowaniu. Wątek dziedziczy swój priorytet po jego rodzicu (wątku).

Daeon Threads - setDaemon(boolean) (standardowy false).

Yielding - zaprzestanie wykonywania i umieszczenie wątku w kolejce Ready. Jeśli jest tylko jeden wątek oczekujący, to yield() nic nie daje. yield() nie powoduje także zaprzestania wątku ze względu na wątki o niższym priorytecie.

wait(), notify() i notifiAll() mogą być wywołane tylko z metody synchronized.

Gdy wywołuje się metodę synchronized - klasa musi dostać lock na dany obiekt (lub całą klasę jeśli metoda jest static).

Rozdział 6. Classes

Overloading Methods
  1. Ta sama nazwa, inna liczba lub typ argumentów.
  2. Różna może być dostępność, zwracany typ, lista wyjątków.
  3. Metoda jest unikalna jeśli chodzi o klasę, w której sie znjaduje, nazwę, typ zwracany, kolejność (typ) i liczbę argumentów.
Metodę definiuje jej nazwa, liczba i rodzaj (kolejność, typ) argumentów.

Overriding Methods
  1. Overloaded muszą mieć inną listę argumentów; Overriding - ten same typy i kolejność argumentów.
  2. Typ zwracany Overloaded method może być dowolny; Overriding - identyczny, lub klasa pochodna typu zwracanego przez parenta.
  3. Overloaded - dowolna liczba wyjątków; Overriding - muszą dziedziczyć po parencie? Albo może nie rzucać wyjątków! Wpp błąd.
  4. Overloaded - dowolny access mofifier; Overloaded - przynajmnije taki jak parent. Wpp błąd.
Konstruktory
super(params), this(params) - możliwość wołania konstruktora klasy nadrzędnej i obecnej. Instrukcje te muszą pojawić się jako pierwsze w konstruktorze. Jeśli w konstruktorze klasy pochodnej nie ma super(params), to kompilator automatycznie wstawi tam wywołanie domyślnego konstruktora klasy nadrzędnej. Jeśli wołamy this(params), kompilator nie wstawia super, lecz odwleka to do wołanego konstruktora. Jeśli klasa dostarcza konstruktor z parametrami, Java nie dostarcza już konstruktora bezparametrowego. Jeśli zaś klasa nie ma zdefiniowanych konstruktorów, Java dostarcza domyślny bezargumentowy.

Klasy wewnętrzne
Klasy wewnętrzne mają dostęp do wszystkich atrybutów i metod (private) klasy zewnętrznej.

public static void main(String args[]) {
OuterOne.InnerOne i = new OuterOne().new InnerOne();
i.innerMethod();
}

jest tym samym co:

public static void main(String args[]) {
OuterOne o = new OuterOne();
OuterOne.InnerOne i = o.new InnerOne();
i.innerMethod();
}

W przypadku definicji statycznej klasy wewnętrznej, nie ma ona dostępu do nie-statycznych pól klasy obudowującej. Stworzenie klasy wewnętrznej nie wymaga w taki wypadku tworzenia klasy obudowującej:
MyInner aMyInner = new MyOuter.MyInner();

Klasy wewnątrz metod
  1. Klasy zadeklarowanie wewnątrz meotdy są prywatne i nie mogą mieć żadnego modyfikatora zakresu.
  2. Meotdy te mogą odwoływać się do zmiennych klasy (też prywatnych) oraz finalnych zmiennych używanych wewnątrz metody.

public void go(int x, final int y) {
int a = x + y;
final int b = x - y;
class MInner {
public void method() {
System.out.println(“m is “ + m);
// System.out.println(“x is “ + x); //Illegal!
System.out.println(“y is “ + y);
// System.out.println(“a is “ + a); //Illegal!
System.out.println(“b is “ + b);
}
}
MInner that = new MInner();
that.method();
}


Klasa anonimowa
  1. Może extends lub implements (nie oba na raz i tylko 1 interface) - nie używa się nawet słów kluczowych implements czy extends.
  2. Klasa anonimowa nie może posiadać zaimplementowanego przez siebie konstruktora, bo nie ma nazwy. Można jednak użyć nie domyślnego konstruktora:

Button b = new Button(“Anonymous Button“) {
...
};


Enumerations
  1. Można deklarować wtedy co klasy.
  2. Podczas kompilacji generowany jest plik .class z enum'em.
  3. Dziedziczy po Object.
  4. Może zawierać main().
  5. Jeśli enum posiada atrybut bez wartości w (), musi dostarczyć domyślny konstruktor.

enum Suit {
DIAMOND(true), HEART(true), CLUB(false), SPADE(false);

private boolean red;

Suit(boolean b) {
red = b;
}

public boolean isRed() {
return red;
}

public String toString() {
String s = name();
s += red ? ":red" : ":black";
return s;
}
}

Rozdział 5. Flow control, Exceptions, Assertions

Pętla for składa się z trzech części. Pierwsza - deklaracja albo przypisanie (nie 2 w jednym momencie). Deklaracja lub przypisanie może odtyczyć kilku zmiennych oddzielonych przecinkiem. Przecinkiem oddzielone mogą być także składniki trzeciej części pętli. Każda część pętli for jest opcjonalna.

mainLoop: for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[i].length; j++) {
if (array[i][j] == ‘\u0000’) {
continue mainLoop;
}
}
}

mainLoop: for (i = 0, j = 0; i < 3; ++i, ++j) {
System.out.println("main loop");
for (int x = 0; x < 1; ++x) {
if (x == 0) {
System.out.println("x = 0");
break mainLoop;
}
}
}

W przypadku switch zmienna warunkowa musi być "assignment compatible" z int (czyli. byte, short, char lub int). Wyrażenie po slowie kluczowym "case" musi być wartością lub stałą.

Wyjątki

Jeśli metoda ma w deklaracji "throws", jej wywołanie musi być otoczone odpowiednim blokiem try-catch. Inaczej nastąpi błąd kompilacji. Gdy nie ma bloku catch dla danego wyjątku, JVM wypisuje stack trace i kończy działanie. Nie trzeba łapać, ani obsługiwać (throws) wyjątków dziedziczących po RuntimeException! Przy przeciązaniu funkcji, zadeklarowane wyjątki muszą dziedziczyć po wyjątku zadeklarowanym w funkcji pierwotnej.

Funkcje rozróżniane są przez nazwę oraz parametry, nie przez wartość zwracaną.

Blok finally jest zawsze wykonywany, nawet jak zaden z catch nie obsłużył wyjątku. Finally może się nie wykonać w przypadku śmierci wątku, System.exit() lub wyłączeniu komuptera.

Asercje

assert Expression1
assert Expression1:Expression2

Expression1 musi być boolowskie. Asercje trzeba włączyć w JVM (java -ea MyApp), jeśli są wyłączone nic nie robią. Jeśli Expression1 == true, żadna dalsza akcja nie jest wykonywana, jeśli jest false - rzucany jest wyjątek AssertionExcpetion oraz opcjonalnie dodawane do niego Expression2 jako wiadomość (toString).

Rozdział 4. Converting and Casting

Konwersja typów prostych:
  1. boolean nie może być rzutowany na inny typ.
  2. typ mniejszy może być niejawnie rzutowany na typ większy, np. pod zmienną double podstawiamy zmienna int.
  3. typ większy nie może być niejawnie rzutowany na typ mniejszy, np. double na int.
Legalne przypisanie: ((char)||(byte->short))->int->long->float->double
W Javie zmienne liczbowe są explicite tylko int albo double (float f = 1.234; // błąd kompilacji). Ale przypisanie liczby całkowitej do byte, short albo char nie powoduje błędu.
Przy przekazywaniu parametrów do wywołania metody następuje promocja argumentu. Jeśli typ wymagany jest mniejszy - błąd kompilacji.

Przy rzutowanie na typ większy (numeryczny) nie traci się wartości.

Promocja w przypadku działań:
1. Operatory unarne:
a) Jeżeli operand jest byte, short lub char, a operator to nie ++ ani --, to następuje promocja do int.
b) wpp nic się nie dzieje.
2. Operatory binarne (2 argumentowe)
a) Jeżeli jeden z operandów jest double, drugi konwertowany jest do double.
b) Jeśli jeden z opeandów to float, drugi konwersja do float.
c) long, long...
d) wpp oba do int.

Aby zawęzić wartość zmiennej, należy zastosować explicite cast. Nie można rzutować boolean na nic, ani nic na boolean.

Konwersja referencji:
  1. Konwersji podlegają referencje na obiekty, interfejsy i tablice.
  2. Interfejs może ulec konwersji na interfejs lub klasę. Jeśli jest to interfejs, to musi być to interfejs bazowy danego interfejsu.
  3. Klasa może ulec konwersji na klasę oraz interfejs. Klasa musi być klasą bazową, a interfejs musi być implementowany.
  4. Tablica może uleca konwersji na klasę Object, interfejs Cloneable lub Serializable, lub na tsblicę. Tylko konwersja tablicy zawierającej referencje do obiektów, na inną tablicę, gdzie typy obu obiektów moża konwertować, jest dozwolone.
Wszystko można przypisać do Object, nawet tablice.

TODO: Tabelka na stronie 148.

Nie można rzutować klasy finalnej na interfejs, ale każdą inną można - nie ma błędu kompilacji, lecz będzie Exception podczas runtime.

Rozdział 3. Modifiers

The Access Modifiers
  1. Klasy nie wewnętrzne mogą być tylko public.
  2. Metody public mogą być przeciążone przez klasy pochodne.
  3. Klasy pochodne nie mają dostępu do prywatnych zmiennych, metod, czy klas wewnętrznych.
  4. Dostęp domyślny - każdy obiekt znajdujący się w tym samym pakiecie ma dostęp do danego atrybutu.
  5. Tylko zmienne i metody mogą być protected. Do obiektów protected mają dostęp wszystkie obiekty z tego samego pakietu, jak i klasy, które dziedziczą po danym obiekcie, a są w innym pakiecie.
  6. Obiekty o niższej dostępności mogą być przeciążane przez klasy pochodne, jeśli ten nadają taką samą dostępność lub większą. Dla przykładu, metoda private void xxx(), może zostać przeciążona w klasie pochodnej na public void xxx().
Final powoduje, że metod nie można przeciążać, a referencja (nie obiekt) musi pozostać stała. W szczególności finalny typ prosty nie może zostać zmieniony. Finalna metoda musi posiadać ciało.

Klasa musi zostać zadeklarowana jako abstrakcyjna gdy posiada jedną lub więcej abstrakcyjnych metod, klasa dziedzicz jakąś abstrakcyjną metodą z innej klasy, dla której nie udostępnia implementacji; lub klasa implementuje interfejs, lecznie nie zawiera implementacji dla każdej z jego metod. Klasa nie może być abstrakcyjna i finalna, ale abstrakcyjna klasa może posiadać finalne metody. Metoda nie może być jednocześnie finalna i abstrakcyjna.

W metodach static nie można uzywać this. Statycznych metod nie można przeciążyć jako nonstatic. Kod wewnątrz static {} wywoływany jest dokładnie raz kiedy klasa jest ładowana. Zmienne public, protected i default mogą być static import do klas w obrębie tego samego pakietu. Do innych pakietów, mogą być tylko pubic.

Native może dotyczyc tylko metody.

Volatile - zmienna może być dostępna asynchronicznie, istotne w środowiskach wieloprocesorowych.

TODO: Nauczyć tabelki na stronie 124.