Kurs Komputerowy

http://www.fizyka.umk.pl/~piotra/dydaktyka/Java

Piotr Ablewski

Katedra Informatyki Stosowanej Instytut Nauk Technicznych Wydział Fizyki Astronomii i Informatyki Stosowanej Uniwersytet Mikołaja Kopernika w Toruniu mgr inż. Piotr Ablewski www.fizyka.umk.pl/~piotra e-mail: piotra@fizyka.umk.pl lub [email protected] Discord: https://discord.gg/84yCUWz ← kurs_komputerowy_java Telegram: https://t.me/PiotrA_KIS_UMK

Konsultacje: środa 12:00 - 14:00 lub w dowolnym umówionym mailowo terminie - jestem dostępny od poniedziałku do piątku od 12:00 do 20:00, za wyjątkiem czasu, gdy prowadzę zajęcia.

Gdzie mnie szukać: pokój 571 (na przeciwko wejścia do PK1 i PK2) Zasady zaliczenia przedmiotu

● Obowiązkowa obecność na laboratoriach - dopuszczalne dwie nieobecności nieusprawiedliwione ● Na ostateczną ocenę składa się: ○ Kolokwium - 30% wkładu do oceny [termin zostanie ustalony] ○ Projekt zaliczeniowy - 40% wkładu do oceny [tematy zostaną podane w ok. ¾ zajęć] ○ Praca na zajęciach - 30% wkładu do oceny [bieżąca praca polegająca na realizacji zadań] ● W ramach zajęć można otrzymać łącznie max. 100 pkt., z czego 50 pkt. niezbędnych jest do otrzymania zaliczenia

Java początki prac: 1991 r. pierwsze informacje: 1995 r. pierwsza wersja dostępna publicznie: 1996 r.

Twórca: @ (współpraca: Mike Sheridan, i Patrick Naughton)

Project Green -> Oak -> Java

Obecnie Java rozwijana jest przez firmę Oracle (w 2010 roku Sun został przejęty przez Oracle) Założenia twórców

1) Język w pełni obiektowy, tak dobry i szybki jak ++, ale dużo łatwiejszy w wytwarzaniu oprogramowania 2) Write once, run anywhere - maszyna wirtualna 3) Uniwersalny język ogólnego przeznaczenia Założenia twórców

1) Język w pełni obiektowy, tak dobry i szybki jak C++, ale dużo łatwiejszy w wytwarzaniu oprogramowania i o bardziej klarownej składni 2) Write once, run anywhere - maszyna wirtualna 3) Uniwersalny język ogólnego przeznaczenia Zastosowanie

1) Odbiorniki telewizyjne 2) Aplikacje okienkowe 3) Aplikacje mobilne (JavaME - Siemens, Nokia, Sony Ericsson, Android) 4) Aplikacje webowe 5) Aplikacje serwerowe 6) Programowanie sieciowo-komunikacyjne 7) Dydaktyka sieci komputerowych i systemów operacyjnych ( olbrzymie wsparcie Sun’a a następnie Oracle’a) Siemens SL45i - pierwszy telefon obsługujący Java ME

Java, JVM, JRE, Java ME, Java EE - o co chodzi?

Java - język programowania

JVM - - maszyna wirtualna, na której uruchamiać można oprogramowanie napisane w językach:

● Java ● Scala ● Kotlin ● Groovy ● ● JRuby (Ruby) ● (Python) Java, JVM, JRE, Java ME, Java EE - o co chodzi?

Platformy Java:

● Java Standard Edition (Java SE) - aplikacje uruchamiane w konsoli lub aplikacje okienkowe ● Java Enterprise Edition (Java EE) - aplikacje serwerowe ● Java Micro Edition (Java ME) - aplikacje mobilne lub działające na urządzeniach o niskiej wydajności ● Java FX - aplikacje RIA (rich internet applications) oraz aplikacje okienkowe ● - mikro aplikacje uruchamiane na kartach elektronicznych

Platforma Java to zbiór bibliotek i narzędzi umożliwiających lub ułatwiających tworzenie oprogramowania dla konkretnych zastosowań. Java, JVM, JRE, Java ME, Java EE - o co chodzi?

JRE - Java Runtime Environment - środowisko uruchomieniowe dla aplikacji napisanych w języku Java, na które składa się JVM + podstawowe klasy pomocnicze (minimum do uruchomienia programu w Javie).

JDK - - darmowe oprogramowanie udostępniające środowisko niezbędne do programowania w języku Java, składające się z :

● javac – kompilatora ● jar – archiwizatora ● javadoc – generatora dokumentacji ● javah – generatora plików nagłówkowych ● javap – deasemblera ● jdb – debuggera Skąd i co pobrać

JRE: https://www.java.com/pl/download/

JDK + Docs: https://www.oracle.com/java/technologies/javase-downloads.html Implementacje Java i biblioteki

● OpenJDK: 2006 - 2014 @ GNU GPL ● HotSpot (JRE): 1999 - obecnie, od 2006 r. @ GNU GPL ● KVM: Kilobyte Virtual Machine stworzona dla urządzeń wyposażonych w procesory 16- i 32-bitowe, pracujące z częstotliwością 12 - 60 MHz, oraz min. 128 kB pamięci RAM ● Kaffe ● Apache, IBM, RedHat Foundation itp.

Zainteresowanym polecam zajrzeć tutaj: https://en.wikipedia.org/wiki/List_of_Java_virtual_machines IDE - Netbeans IDE - IDE - IntelliJ IDEA IDE - Visual Studio Code IDE - VIM lub Emacs lub Nano/Pico lub mcedit Kolejna mała wojenka... Zajęcia 3.

Mechanizmy programowania obiektowego Definicja klasy

Complex.java Definicja paczki package com.UMK;

public class Complex Nazwa klasy { private double re; private double im; Pola klasy

public Complex() { Konstruktor this.re = 0.0; this.im = 0.0; } Metody klasy

public Complex(double re, double im) { this.re = re; this.im = im; } ... } Instancjonowanie klasy

Main.java

package com.UMK;

public class Main {

public static void main(String[] args) Klasa - definicja, jak wyglądać ma { obiekt // poprzez ładowanie klasy Class klasa_complex = Class.forName("Complex"); Complex a = klasa_complex.newInstance(); Obiekt - instancja klasy; niezależny byt klasy, mający przypisane swoje // poprzez new miejsce w pamięci Complex z = new Complex(); } } Modyfikatory dostępu

1. public - klasa, pole lub metoda jest dostępna publicznie

2. private - pola i metody nie są widoczne poza klasą, klasa prywatna nie jest widziana poza modułem, w którym jest zdefiniowana

3. protected - pola i metody dostępne są dla danej klasy i jej podklas oraz innych klas w tym samym pakiecie; modyfikator nie jest dostępny dla klasy

Domyślnie klasy, pola i metody przyjmują modyfikator package private (default) - element widoczny będzie tylko w ramach pakietu, w którym jest zadeklarowany! Modyfikatory dostępu - cel

Głównym celem modyfikatorów dostępu jest enkapsulacja (hermetyzacja), czyli ukrycie szczegółów dotyczących implementacji klasy. Dzięki temu ostateczny użytkownik klasy ma dostęp tylko do ściśle określonych funkcjonalności. W przypadku dziedziczenia - można budować skomplikowane relacje między obiektami.

Zasady stosowania modyfikatorów dostępu: ● stosowanie jak najbardziej restrykcyjnych modyfikatorów dostępu (w praktyce - pola private, metody public lub private, w zależności od tego, czy użytkownik ma mieć możliwość bezpośredniego wywołania metody, czy też nie) ● tworzenie setterów i/lub getterów dla prywatnych pól, celem ich “odkrywania” Pola klasy - zakres

Pola klasy dostępne są wewnątrz obiektu i na zewnątrz (jeśli pozwala na to modyfikator lub mamy zdefiniowany getter).

Pola domyślnie nie są współdzielone przez obiekty - każdy obiekt ma swój zestaw pól, którym przypisane są konkretne dla niego wartości.

Pola można współdzielić między obiektami tej samej klasy poprzez użycie słówka kluczowego static przy definicji pola, np.: public static int a = 0;

Takie pole można wykorzystać np. jako zmienną przechowującą liczbę instancji danego obiektu. Metody statyczne

Metoda oznaczona jako static pozwala wywoływać się bez konieczności instancjonowania klasy. Można dzięki temu stworzyć klasę, która pozwalać będzie na wywoływanie z niej funkcji (np. klasa Math nie może być instancjonowana, ale można z niej wołać stałe ( Math.E i Math.PI ) oraz metody zwracające wartości funkcji (np. Math.abs(x) zwróci moduł liczby x, która może być typu int, long, float lub double).

Podstawową metodą statyczną jest metoda main, której implementacja wygląda następująco: public static void main(String[] args) { … } Oznacza to, że uruchomienie programu nie jest związane z żadnym obiektem. Na początku mamy tylko główną klasę Main i w ramach metody main(), będącej punktem wejścia programu, implementujemy całą logikę. Nigdzie nie wołamy bezprośrednio konstruktora klasy Main i nie wywołujemy na obiekcie tej klasy metody main(). Klasy statyczne

Metody statyczne wykorzystuje się jako substytut zwykłych funkcji, które można wywołać bez konieczności tworzenia obiektu. Bardzo często buduje się klasy statyczne oparte na metodach statycznych, które działają jak wspomniana wcześniej klasa Math. W pełni statyczna klasa nie może dać się instancjonować, a nie można użyć w jej definicji słowa static. Efekt ten uzyskuje się poprzez prywatny konstruktor.

Main.java ComplexMath.java

package com.UMK; package com.UMK;

public class ComplexMath public class Main { { private ComplexMath() { } public static void main(String[] args)

{ public static double module( Complex z ) Complex x = new Complex(); { ComplexMath.module(x); return Math.sqrt(z.getRe()*z.getRe() + z.getIm()*z.getIm()); } } } } Klasy statyczne - cd

W języku Java istnieje jeden przypadek, gdzie do definicji klasy można dodać słowo static - tworzyć można zagnieżdżone klasy statyczne (ang. inner class) - w tym przypadku do ich instancjonowania nie ma potrzeby, aby w pierwszej kolejności instancjonować klasę zewnętrzną. Oczywiście taka klasa wewnętrzna ma dostęp jedynie do statycznych pól i metod klasy zewnętrznej. Jest to kolejny sposób na jeszcze szczelniejszą enkapsulację.

Klasa zagnieżdżona statyczna Klasa zagnieżdżona

public class Foo { public class Foo { public class Bar{ } public static class Bar{ } } } public class Main { public class Main { public static void main(String[] args) public static void main(String[] args) { { Foo foo = new Foo(); Foo.Bar Bar = new Foo.Bar(); Foo.Bar Bar = new Foo.new Bar(); } } } }

Metody statyczne - pułapki

Z poziomu metody statycznej nie możemy wywołać metody stricte obiektowej, bo musi być ona związana z konkretną instancją klasy. Aby obejść ten problem, wewnątrz metody statycznej tworzy się instancję klasy i dopiero na stworzonym obiekcie wywołuje się metodę obiektową. Rozwiązanie wydaje się być dość osobliwe, ale potrafi być użyteczne. Stosuje się je niezwykle rzadko, ale potrafi ono poprawić enkapsulację klasy - z poziomu metod statycznych można zwracać utworzone obiekty, a więc metody takie mogą działać jako swoiste substytuty konstruktorów. Metody takie nazywa się statycznymi metodami wytwórczymi (ang. static factory method).

Bloki statyczne

Wewnątrz klasy można stworzyć blok statyczny, którego zawartość zostanie wywołana przed utworzeniem obiektu, a więc przed wywołaniem konstruktora klasy.

Main.java Foo.java

package com.UMK; package com.UMK;

public class Foo{ public class Main static{ { System.out.println("HELLO WORLD SPRZED KONSTRUKTORA"); public static void main(String[] args) } { public Foo(){ Foo foo = new Foo(); System.out.println("HELLO WORLD Z KONSTRUKTORA"); } } } }

Klasy abstrakcyjne

Klasa abstrakcyjna jest klasą, której nie można instancjonować. Jest ona klasą ogólną i służy jako szkielet do budowy innych klas. Może zawierać gotowe definicje metod, jak również deklaracje metod, które informują jedynie o typach - zarówno tych przyjmowanych przez metodę, jak i przez nią zwracanych. Metody takie nazywane są metodami abstrakcyjnymi i oznaczane są modyfikatorem abstract. Klasy abstrakcyjne posiadają zarówno normalne, zdefiniowane metody jak i metody abstrakcyjne. Dzięki temu rozwiązaniu wszystkie klasy zbudowane na podstawie klas abstrakcyjnych będą implementowały określone metody. Ciała metod abstrakcyjnych będą musiały zostać wypełnione przy definiowaniu klasy zbudowanej na podstawie klasy abstrakcyjnej. Interfejsy

Interfejsy są rozszerzeniem klas abstrakcyjnych - zawierają one jedynie abstrakcyjne metody oraz statyczne i stałe pola. Są one swoistym wzorcem, według którego buduje się klasę. Różnią się one od klas abstrakcyjnych tym, że żadna z metod nie jest zdefiniowana. Interfejsy są przez klasy implementowane, nie rozszerzając ich funkcjonalności, a definiując zbiór metod i pól, które w klasie muszą wystąpić. Do ich deklaracji używa się słowa kluczowego interface. Metody implementowane przez interfejs oznaczane są poprzez adnotację @Override. Kot.java Garfield.java

public interface Kot public class Garfield implements Kot { { public String pokarm = "Kocie chrupki"; @Override public static float ile_lap = 4; public String odglos(){ return "Miauuu..."; } public String odglos(); @Override public void spij(float czas); public void spij(float czas){ System.out.println("ChrapuChrapu"); } } public String pokarm = "Lasagne"; }

Klasy anonimowe

Klasa anonimowa to klasa definiowana “w locie”, mająca dokładnie jedną instancję (chociaż później nauczymy się je multiplikować wykorzystując mechanizm refleksji). Klasa anonimowa jest zawsze klasą wewnętrzną.

Main.java Zwierze.java

public class Main

{

public static void main(String[] args){

Zwierze kot = new Zwierze(){ public interface Zwierze @Override { public void dajGlos(){ public void dajGlos(); System.out.println("Miauuu..."); } }

};

kot.dajGlos();

}

} Klasy anonimowe - drobna uwaga

Klasa anonimowa, pomimo tego, że trochę tak wygląda, nie jest sposobem na instancjonowanie interfejsów. Interfejs jest tutaj jedynie wzorcem, według którego klasa anonimowa ma zostać zbudowana.

Trzeba również zwracać szczególną uwagę na dostęp do zmiennych - np. umieszczenie zmiennej w ciele metody, w której zdefiniowano klasę anonimową korzystającą z tej metody spowoduje błąd. Aby wszystko działało poprawnie, należy zmienną, z której korzysta się w klasie anonimowej oznaczyć słowem final.

Mechanizm klas anonimowych wykorzystywało się do przekazywania metod do metod, lecz brak czytelności tego rozwiązania wymógł implementację mechanizmu lambd (o tym później). final - zmienne

Zmienna oznaczona słowem final może mieć przypisaną wartość jedynie raz (zazwyczaj w trakcie deklaracji). Jeśli zmienna final dotyczy obiektu to wartością zmiennej jest wartość referencji, a nie sam obiekt. Oznacza to, że można modyfikować wartości pól tego obiektu (pod warunkiem, że nie są one oznaczone jako final), ale do zmiennej nie można po raz kolejny przypisać obiektu (nawet tego samego).

Main.java Zwierze.java

public class Main { public class Zwierze final Zwierze piesek = new Zwierze(); { public final int ile_lap = 4; piesek.ile_lap = 8; // To nie zadziała public String imie = ""; piesek = new Zwierze(); // To nie zadziałą } piesek.imie = "Burek"; // A to zadziała

} final - metody

W języku Java wszystkie metody są wirtualne, tzn. można je nadpisać w klasach potomnych. Aby zablokować tę możliwość, metodę oznaczyć należy jako final. Implementacja takiej metody musi znaleźć się w klasie, w której została zdefiniowana i nie będzie można jej później zmienić. Mechanizm ten ma na celu zapobieganie zmianom kluczowych metod w klasach, które wykorzystywane są jako klasy bazowe dla innych klas.

Konkretne przykłady pojawią się na zajęciach dotyczących dziedziczenia w języku Java. final - klasy

Klasa oznaczona jako final nie może być wykorzystana jako klasa bazowa dla innej klasy. Oznacza to, że dodanie słowa final przed definicją klasy powoduje, że będzie można ją jedynie instancjonować. W klasie finalnej wszystkie metody i pola są z góry finalne. Celem tego mechanizmu jest zapewnienie bezpieczeństwa, ograniczenie możliwości dziedziczenia po każdej klasie, a czasami zwiększenie efektywności wytworzonego kodu.

Konkretne przykłady pojawią się na zajęciach dotyczących dziedziczenia w języku Java. Typy ogólne (generyczne)

Typy ogólne są swoistymi szablonami - można dzięki nim tworzyć klasy, które operować będą na dowolnym typie danych. Dzięki temu uniknąć można multiplikowania implementacji klas, które operować mają na różnych typach danych (np. liczba zespolona może mieć pola typu int, float, double itp.) oraz zniwelować niepotrzebne rzutowania. Poniżej przedstawiono przykład implementacji klasy Complex działającej na typie ogólnym T. Typ T zostanie skonkretyzowany przy instancjonowaniu obiektu klasy Complex. Pamiętać należy, że typy ogólne konkretyzować można jedynie typami obiektowymi (np. java.lang.Integer, java.lang.Float, java.lang.Double) - nie można korzystać z typów prostych (np. int, float, double).

Main.java Complex.java package com.UMK; public class Main { package com.UMK; public class Main{ public class Complex public static void main(String[] args){ { Complex complexInt = new Complex(); private T re; Complex complexFloat = new Complex(); private T im; } /* settery, gettery i metody */ } } } Zajęcia 4.

Dziedziczenie w języku Java

Dziedziczenie

Niektóre, z tworzonych przez nas obiektów mogą mieć wiele wspólnego. Dlatego, aby ograniczyć potrzebę wielokrotnej implementacji tych samych funkcjonalności, paradygmat programowania obiektowego wprowadza dziedziczenie. Dziedziczenie to nic innego, jak współdzielenie funkcjonalności jednej klasy przez drugą klasę. Klasa udostępniająca funkcjonalność nazywa się klasą bazową (czasami mówi się o niej superklasa lub nadklasa), a klasa korzystająca z tej funkcjonalności to klasa pochodna (klasa potomna, podklasa).

W języku Java dziedziczenie oznaczane jest przez słowo extends - mówi to jasno, że klasa pochodna rozszerza funkcjonalność klasy bazowej.

Klasa w języku Java może explicite dziedziczyć tylko po jednej klasie bazowej, ale można stworzyć łańcuch dziedziczenia (klasa bazowa dla danej jest klasą pochodną od innej klasy). Jednak takie rozwiązanie jest zalecane, ze względu na skomplikowanie kodu. Diagramy UML Student + NumerIndeksu - pobieraStypendium

Osoba + zdajEgzamin() + napiszKolokwium() + Imię + Nazwisko - PESEL Uczeń + przedstawSię() - zagłosuj() + NumerWDzienniku

+ napiszKlasówkę() - zagłosuj() Dziedziczenie - przykład

Osoba.java Student.java public class Osoba{ public class Student extends Osoba{ public String imie; public String numerIndeksu; public String nazwisko; private boolean pobieraStypendium; protected String PESEL; public Student(String imie, String nazwisko, String PESEL, ………………………….String numerIndeksu){ public Osoba(String imie, String nazwisko, String PESEL){ super(imie, nazwisko, PESEL); this.imie = imie; this.numerIndeksu = numerIndeksu; this.pobieraStypendium = false; this.nazwisko = nazwisko; } this.PESEL = PESEL; public void setStypendium(){ } this.pobieraStypendium = true;

} public String przedstawSie(){ private String glosuj(){ return "Nazywam się " + imie + " " + nazwisko; return "Głosuję na kandydata z Partii Miłośników Piwa"; } }

public int zdajKolokwium(){ protected String glosuj(String kandydat){ return 5; return "Głosuję na " + kandydat; } } } } Dziedziczenie a modyfikatory dostępu

public -> pola i metody widoczne w klasach potomnych protected -> pola i metody widoczne w klasach potomnych, ale nie widoczne na zewnątrz tych klas private -> pola i metody nie są widoczne dla klas potomnych Przesłonięcie metody w klasie potomnej

W klasie bazowej i potomnej możemy mieć metodę o tej samej nazwie. Która z nich zostanie wywołana? W klasie bazowej - ta z klasy bazowej, a w klasie potomnej - ta, z klasy potomnej. Aby w klasie potomnej wywołać metodę z klasy bazowej należy użyć słowa super, np.: MojaKlasa.java public class KlasaPotomna extends KlasaBazowa { public void metoda() { super.metodaZKlasyBazowej(); } } Aby ułatwić sobie przesłanianie - korzysta się z adnotacji @override - mówi ona kompilatorowi, że metoda ta ma przesłaniać metodę w klasie bazowej. Dodatkowo - ułatwia czytanie kodu, ponieważ od razu widać, że jest to reimplementacja metody z klasy bazowej. Przeciążenie metody w klasie potomnej

Przeciążenie metody nie jest stricte związane z dziedziczeniem. Przeciążenie metody to stworzenie metod o takiej samej nazwie, ale o innej liście parametrów. Można to uczynić zarówno w jednej klasie, jak i również w klasie potomnej. Klasa potomna może mieć metodę o tej samej nazwie, ale o innej liście parametrów - przez to wraz z zawołaniem metody z różnymi argumentami, wołana będzie inna implementacja metody (z klasy bazowej lub potomnej). Dziedziczenie konstruktorów

Konstruktory przy dziedziczeniu zachowują się jak metody - mamy do nich dostęp w klasie potomnej.

Domyślnie, wołany jest implicite konstruktor domyślny klasy bazowej, a następnie konstruktor klasy potomnej (warto prześledzić na prostym przykładzie w IDE).

Jeśli zależy nam na zawołaniu konstruktora klasy bazowej explicite - można zrobić to poprzez konstrukcję super() - jako parametry podać należy parametry przyjmowane przez konstruktor klasy bazowej (jeśli oczywiście są one zdefiniowane). Java Object

Pomimo tego, że każda klasa może dziedziczyć jawnie po jednej klasie bazowej, to dziedziczy ona również implicite po klasie Object. Każdy typ obiektowy w języku Java jest typem pochodnym od typu Object (zwanym bardzo często superklasą), pomimo, że nie używa się wprost poniższej deklaracji:

MojaKlasa.java

public class MojaKlasa extends Object { ... } Java Object

Dzięki temu rozwiązaniu mamy zapewnioną implementację (którą możemy oczywiście póżniej nadpisać) dla metod taki jak:

● clone() ● equals(Object obj) ● finalize() ● getClass() ● hashCode() ● toString() Oraz metody związane z wątkami, o których szerzej będzie później. Dziedziczenie - lek na problemy z Complex

Warto zajrzeć do dokumentacji klas Number i na przykład Double (dowolnej, która dziedziczy po Number): https://docs.oracle.com/javase/8/docs/api/java/lang/Number.html https://docs.oracle.com/javase/8/docs/api/java/lang/Double.html

Można też przyjrzeć się interfejsowi Comparable: https://docs.oracle.com/javase/8/docs/api/java/lang/Comparable.html

I Java 10 - var, czyli dynamiczne typowanie

W wersji 10. języka Java pojawiło się słowo kluczowe var, pozwalające na zdefiniowanie zmiennej, bez określania jej typu explicite. Jest to ukłon w stronę języków słabo typowanych (np. JavaScript lub Python), gdzie typy zmiennych ustalane są na etapie wykonywania kodu (interpretera).

Pod żadnym pozorem nie wolno utożsamiać słowa var z wprowadzeniem do Javy słabego typowania identycznego z tym, stosowanym w JavaScripcie. Zamysłem twórców było ułatwienie definiowania zmiennych, których klasy mają długie nazwy, ale można czasami skorzystać z “lukru składniowego” i ułatwić sobie zapis typu zmiennej przez var, pamiętając o typach wynikowych i o tym, co “pod spodem” zrobi platforma Java.

UWAGA! var bywa zgubne i mechanizmu tego nie powinno się nadużywać! Java 10 - var, czyli dynamiczne typowanie

Poprawne użycie var

FileReader fr = new FileReader("plik.txt"); BufferedReader reader = new BufferedReader(fr);

var fr = new FileReader("plik.txt"); var reader = new BufferedReader(fr); Java 10 - var, czyli dynamiczne typowanie

Does this make Java dynamically typed? Is this like var in JavaScript? No and no. Java is still a statically typed language, and the addition of var doesn't change this. var can be used in a local variable declaration instead of the variable's type. With var, the Java compiler infers the type of the variable at compile time, using type information obtained from the variable's initializer. The inferred type is then used as the static type of the variable. Typically, this is the same as the type you would have written explicitly, so a variable declared with var behaves exactly as if you had written the type explicitly.

[Źródło: https://openjdk.java.net/projects/amber/LVTIFAQ.html] Dziedziczenie - trochę praktyki

Wyposażeni w narzędzie, jakim jest dziedziczenie - przejdźmy do IntelliJ Idea i spróbujmy poprawić klasę Complex z poprzednich zajęć.

Postarajmy się, aby napisać jak najmniej i zrobić to w jak najbardziej optymalny sposób. Zajęcia 5.

Współbieżność w języku Java Współbieżność - przypomnienie

Współbieżność to możliwość jednoczesnego wykonywania kilku zadań.

W rozumieniu systemu operacyjnego - wykonywanie kilku programów (procesów) jednocześnie. W rozumieniu programu komputerowego - wykonywanie kilku wątków jednocześnie. Współbieżność - przypomnienie

Proces - wykonujący się program wraz z dynamicznie przydzielanymi mu przez system operacyjny zasobami (pamięcią operacyjną, zasobami plikowymi, czasem CPU) oraz innymi kontekstami wykonania programu (np. obiektami tworzonymi przez program) . Procesy współzawodniczą o zasoby, zgłaszają na nie zapotrzebowanie zarządcy, który zasoby przydziela. Wykonanie równolegle dwóch lub kilku procesów nie zawsze musi być szybsze niż ich wykonanie synchroniczne! Procesy mogą się ze sobą komunikować i współdzielić zasoby, ale domyślnie każdy z nich posiada swoją odrębną przestrzeń adresową i zasoby.

Wątek - sekwencja działań, która może wykonywać się równolegle z innymi sekwencjami działań w kontekście jednego procesu. Wątki z zasady nie współzawodniczą o zasoby, tylko dzielą je między siebie, starając się nie spowalniać innych wątków (chociaż nie jest to regułą). Wiele wątków może działać w ramach jednego procesu, operując na innych lub tych samych danych, wątki mogą się ze sobą bez problemu komunikować, bo działają w ramach wspólnego procesu. Współbieżność - problemy Współbieżność - problemy Współbieżność - metody przełączania wątków

W systemach jednoprocesorowych efekt równoległego wykonania kilku procesów zyskuje się poprzez przełączanie wątków - zarządca przydziela kwant czasu procesora procesowi, który wykonywany jest przez wątki i następuje przełączenie kontekstu po zużyciu swojego czasu lub zakończeniu pracy wątku. W systemach wieloprocesorowych - kilka procesów może być wykonywanych jednocześnie (rzeczywiście równocześnie) + możliwa jest implementacja przełączania wątków.

Metody przełączania wątków: ● Współpraca - wątek sam decyduje, kiedy oddać zasoby innym wątkom (jeśli oczywiście zasoby te są przydzielone do procesu, w ramach którego działa wątek) ● Wywłaszczanie - zarządca przydziela wątkowi kwant czasu procesora, po jego wykorzystaniu wątek ma zabierane zasoby, które przydzielane są innemu wątkowi Gdzie wykorzystywać wiele wątków

1. Tam, gdzie pozwalają na to zasoby 2. interfejsy graficzne powinny pracować w osobnych wątkach, aby wykonanie programu nie blokowało interfejsu 3. pobieranie danych z plików, serwisów WWW, końcówek sieciowych czy baz danych 4. wszędzie tam, gdzie będziemy oczekiwać na dane lub wykonanie funkcji, której czas wykonania jest zauważalny Wątki w języku Java - klasa Thread

Do implementacji wielowątkowości w języku Java służy klasa Thread. Jeśli chcemy, aby nasza klasa działała wielowątkowo - powinna ona rozszerzać klasę Thread.

Metody superklasy Thread: ● run() - metoda zawierająca kod, który ma się wykonać w nowym wątku, nie jest wołana explicite ● start() - metoda startująca nowy wątek, wykonujący zawartość metody run() ● interrupt() - metoda pozwalająca przerwać wykonywanie bieżącego wątku

● activeCount() - zwraca liczbę aktywnych wątków w danej klasie [int] ● enumerate(Thread[] tarray) - kopiuje aktywne wątki klasy do tablicy tarray i zwraca liczbę tych wątków ● sleep(long ms) - usypia wątek na ms milisekund ● yeld() - wywłaszcza wątek, przekazując zasoby innemu wątkowi, jeśli ten istnieje Wątki w języku Java - klasa Thread

Metody superklasy Thread - cd: ● setName(string Name) - ustawia nazwę wątku ● getName() - zwraca nazwę wątku ● setDaemon() - daemonizuje wątek ● isDeamon() - zwraca informację, czy wątek działa jako daemon ● setPriority() - ustawia priorytet wątku ● getPriority() - zwraca priorytet wątku ● isAlive() - zwraca informację, czy wątek jest wykonywany ● isInterrupt() - zwraca informację, czy wątek jest zawieszony ● getState() - zwraca informację o stanie wątku ● join() - powoduje synchronizację wątków (czeka na zakończenie wątku) Pozostałe metody: Java 8 - https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html Java 10 - https://docs.oracle.com/javase/10/docs/api/java/lang/Thread.html

Wątki w języku Java - klasa Thread

Timer.java

public class Timer extends Thread { private long seconds;

@Override public void run(){ while ( true ){ seconds++; try{ this.sleep(1000); }catch ( InterruptedException e) { } } } } Wątki w języku Java - klasa Thread

Stany wątków:

● NEW – wątek utworzony i jeszcze nie uruchamiany; program nie zaczął jeszcze wykonywać obecnych w nim instrukcji (zadziałał na razie konstruktor klasy Thread) ● RUNNABLE – stan po wywołaniu run(); wątek może, ale jeszcze nie musi być uruchomiony. ● BLOCKED – wątek jest zablokowany - czeka na powiadomienie z innego wątku (np. zwolnienie zasobów) ● WAITING – wątek jest oczekujący i uśpiony, czeka na jego wywołanie ● TIMED WAITING - wątek jest oczekujący i uśpiony na określony czas ● TERMINATED – wątek zakończył się wraz z końcem instrukcji w metodzie run() lub z powodu wyjątku Wątki w języku Java - interfejs Runnable

A co jeśli nasza klasa już dziedziczy po innej klasie i nie możemy explicite dziedziczyć po klasie Thread?

1. Można zrobić “łańcuch dziedziczenia”, ale to nieeleganckie; ostateczna (niekoniecznie finalna) klasa musi być po prostu wraperem dla klasy dziedziczącej po innej klasie i musi ona dziedziczyć po klasie Thread 2. Nasza klasa dziedzicząca po innej klasie musi implementować interfejs Runnable; takie rozwiązanie jest więc rozwiązaniem “ładniejszym” i w tym przypadku preferowanym Wątki w języku Java - interfejs Runnable

Implementacja interfejsu Runnable wymusza na nas implementację metody run().

Następnie należy utworzyć nowy obiekt klasy Thread, przekazując mu w konstruktorze referencję do obiektu klasy implementującej interfejs Runnable. Na obiekcie klasy Thread można już wołać metody klasy Thread, a metoda run() dostarczona będzie poprzez implementację w klasie implementującej interfejs Runnable. Wątki w języku Java - wyjątki

Wątki mogą rzucać wyjątkami - warto jest więc się przed nimi zabezpieczyć, gdyż nie przechwycony i nieobsłużony wyjątek spowoduje przejście wątku do stanu TERMINATED.

Wyjątki klasy Thread: ● SecurityException - rzucany przez konstruktor; związany z brakiem możliwości utworzenia wątku w zadanej grupie wątków ● IllegalArgumentException - rzucany przez sleep(), gdy czas uśpienia jest niepoprawny ● InterruptedException - rzucany przez wątek, który jest zaburzany przez inny wątek, po rzuceniu wyjątku, wątek wraca do wykonywania swojej pracy ● CloneNotSupportedException - rzucany przez wątek, który nie daje się sklonować (trzeba go kopiować konstruktorem) ● IllegalThreadStateException - stan wątku nie jest poprawny (np. został źle ustawiony) Wątki w języku Java - wyjątki

Metody klasy Thread umożliwiające przechwycenie konkretnego wyjątku lub ustawienie uchwytu do metody go obsługującej:

● getDefaultUncaughtExceptionHandler() ● getUncaughtExceptionHandler()

● setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh) ● setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh) Wątki w języku Java - a co z Object ?

Wcześniej wspominałem, że klasie Object, po której implicite dziedziczy każdy obiekt w języku Java jest również kilka metod do obsługi wątków. Oto one:

● notify() - budzi jeden wątek, który czeka na wykonanie ● notifyAll() - budzi wszystkie wątki, które czekają na wykonanie ● wait() - nakazuje aktualnemu wątkowi czekać na przebudzenie z wykorzystaniem notify() lub interrupt() ● wait (long ms - j. w. lub określa czas po którym wątek zostanie przebudzony z dokładnością do milisekundy ● wait (long ms, int ns) - j. w. z dokładnością do nanosekundy Wątki w języku Java - ćwiczenia

Przykłady implementacji wątków w języku Java - katalog Zajecia5 w projekcie z zajęć (dostępny na GitHubie)

Tym razem - bardzo krótkie zadanie domowe (w pliku na stronie WWW).