Obsah
V tomto předmětu nás z toho bude zajímat jen něco a jen částečně:
Specifikace (tj. zadání a jeho formalizace)
Vývoj (tj. návrh a vlastní programování)
částečně Validace (z ní především testování)
Specifikace SW: Je třeba definovat funkcionalitu SW a operační omezení.
Vývoj SW: Je třeba vytvořit SW, který splňuje požadavky kladené ve specifikaci.
Validace SW: SW musí být validován („kolaudován“), aby bylo potvrzeno, že řeší právě to, co požaduje uživatel.
Evoluce SW: SW musí být dále rozvíjen, aby vyhověl měnícím se požadavkům zákazníka.
Tyto generické modely jsou dále rozpracovávány do podoby konkrétních metodik.
Metodika (tvorby SW) je ucelený soubor inženýrských postupů, jak řízeným způsobem, s odhadnutelnou spotřebou zdrojů dospět k použitelnému SW produktu.
Co bude odlišné oproti dosavadním programátorským zkušenostem?
program měl jeden nebo více zdrojových souborů (soubor = modul) tvořenými jednotlivými procedurami/fcemi, definicemi a deklaracemi (typů, proměnných...)
(a některé další OO jazyky): program je obvykle tvořen více soubory (soubor = popis jedné třídy) tvořenými deklaracemi metod a proměnných (případně dalších prvků) těchto tříd.
v Javě je nezbytná - zdrojové soubory organizujeme podle toho, ve kterých balících jsou třídy zařazeny
Zjistíme, jaké typy objektů se ve zkoumaném výseku reality vyskytují a které potřebujeme
V Javě, na rozdíl od C++ neexistuje vícenásobná dědičnost -
Pokud po třídě chceme, aby disponovala vlastnostmi z několika různých množin (skupin), můžeme ji deklarovat tak, že
Rozhraní je vlastně popis (specifikace) množiny vlastností, aniž bychom tyto vlastnosti ihned implementovali Vlastnostmi zde rozumíme především metody.
Říkáme, že určitá třída implementuje rozhraní, pokud implementuje (tedy má - přímo sama nebo podědí) všechny vlastnosti (tj. metody), které jsou daným rozhraním předepsány.
Javové rozhraní je tedy množina hlaviček metod označená identifikátorem - názvem rozhraní. (a celých specifikací - tj. popisem, co přesně má metoda dělat - vstupy/výstupy metody, její vedlešjí efekty...)
Vypadá i umisťuje se do souborů podobně jako deklarace třídy
Všechny metody v rozhraní musí být public
a v hlavičce se to ani nemusí uvádět.
Těla metod v deklaraci rozhraní se nepíší. (Metody v rozhraní
tudíž vypadají velmi podobně jako abstraktní metody ve třídách, ale
nemusím psát abstract
.)
public interface Informing {
void writeInfo();
}
public class Person implements Informing {
...
public void writeInfo() {
...
}
}
Čteme: Třída Person
implementuje rozhraní
Informing
.
Třída v hlavičce uvede implements NázevRozhraní
Třída implementuje všechny metody předepsané rozhraním
Potřebujeme-li u jisté proměnné právě jen funkcionalitu popsanou určitým rozhraním,
tuto proměnnou můžeme pak deklarovat jako typu rozhraní - ne přímo objektu, který rozhraní implementuje.
Informing petr = new Person("Petr Novák", 1945);
petr.writeInfo(); // "petr" stačí deklarovat jen jako Informing
// jiné metody než předepsané tímto intf.
// nepotřebujeme!
Totéž rozhraní může implementovat více tříd, často konceptuálně zcela nesouvisejících:
Rozhraní Going
("jdoucí") implementují dvě
třídy:
Car
(auto má schopnost "jít", tedy
jet)
Clock
(hodiny také "jdou")
Viz příklad - projekt v BlueJ -
car_clock
V realitě jsme často svědci toho, že třídy jsou podtřídami jiných:
tj. všechny objekty podtřídy jsou zároveň objekty nadtřídy,
např. každý objekt typu (třídy) ChovatelPsu
je
současně typu Clovek
nebo
např. každý objekt typu (třídy) Pes
je
současně typu DomaciZvire
(alespoň v našem
výseku reality - existují i psi "nedomácí"...)
Podtřída je tedy "zjemněním" nadtřídy:
V Javě je každá uživatelem
definovaná třída potomkem nějaké jiné - neuvedeme-li předka explicitně,
je předkem vestavěná třída Object
Nadtřídě (superclass) se také říká "(bezprostřední) předek", "rodičovská třída"
Podtřídě (subclass) se také říká "(bezprostřední) potomek", "dceřinná třída"
Dědění může mít i více "generací", např.
Person
<-
Employee
<- Manager
(osoba
je rodičovskou třídou zaměstnance, ten je rodičovskou třídou
manažera)
Přeneseně tedy předkem (nikoli bezprostředním) manažera je člověk.
Klíčovým slovem extends
:
public class Employee extends Person {
... popis vlastností (proměnných, metod...) zaměstnance navíc oproti člověku...
}
Jak víme, třídy popisují skupiny objektů podobných vlastností
Třídy mohou mít tyto skupiny vlastností:
Vlastnosti jsou ve třídě "schované", tzv. zapouzdřené (encapsulated)
Třída připomíná pascalský záznam (record), ten však zapouzdřuje jen proměnné, nikoli metody.
Dědičnost (alespoň v javovém smyslu) znamená, že dceřinná třída (podtřída, potomek)
Cíl: vylepšit třídu Ucet
Zdokonalíme náš příklad s účtem tak, aby si účet "hlídal", kolik se z něj převádí peněz
Zdokonalenou verzi třídy Account
nazveme CreditAccount
Příklad 1. Příklad kompletního zdrojového kódu třídy
public class CreditAccount extends Account {
// private double balance; znovu neuvádíme
// ... zdědí se z nadtřídy/předka "Account"
// kolik mohu "jít do mínusu"
private double creditLimit;
public void add(double amount) {
if (balance + creditLimit + amount >= 0) {
// zavoláme původní "neopatrnou" metodu
super.add(amount);
} else {
System.err.println("Nelze odebrat částku " + (-amount));
}
}
// public void writeInfo() ... zdědí se
// public void transferTo(Account to, double amount) ... zdědí se
// ... předpokládejme, že v třídě "Ucet" používáme variantu:
// add(-amount);
// to.add(amount);
// }
}
Vzorový zdroják sám o sobě nepůjde přeložit, protože nemáme třídu, na níž závisí.
Klíčové slovo extends
-
značí, že třída CreditAccount
je
potomkem/podtřídou/rozšířením/dceřinnou třídou
(subclass) třídy
Account
.
Konstrukce
super.metoda(...);
značí, že je volána metoda
rodičovské třídy/předka/nadtřídy (superclass).
Kdyby se nevolala překrytá metoda,
super
by se neuvádělo.
Větvení if() {...} else
{...}
- složené závorky se používají k uzavření příkazů
do sekvence - ve smyslu pascalského begin/end.
Demoprojekt
:private_account
Neplést s vícenásobnou - více úrovněmi myslíme častou situaci, kdy ze třídy odvodíme podtřídu, z ní zase podtřídu...
Demoprojekt
:checked_private_account
Přístup ke třídám i jejim prvkům lze (podobně jako např. v C++) regulovat:
Omezení přístupu je kontrolováno hned při překladu -> není-li přístup povolen, nelze program ani přeložit.
Tímto způsobem lze regulovat přístup staticky, mezi celými třídami, nikoli pro jednotlivé objekty
Jiný způsob zabezpečení představuje tzv. security manager, který lze aktivovat při spuštění JVM.
Přístup je v Javě regulován jednotlivě po prvcích
Omezení přístupu je určeno uvedením jednoho z tzv. modifikátoru přístupu (access modifier) nebo naopak neuvedením žádného.
public
public
=> přístupné odevšad
public class Account {
...
}
třída Account
je veřejná =
lze např.
protected
protected
=> přístupné jen z
podtříd a ze tříd stejného balíku
public class Account {
// chráněná proměnná
protected float creditLimit;
}
používá se jak pro metody (velmi často), tak pro proměnné (méně často)
lokální v balíku = přátelský=> přístupné jenze tříd stejného balíku,už ale ne z podtříd, jsou-li v jiném balíku
public class Account {
Date created; // přátelská proměnná
}
používá se spíše u proměnných než metod, ale dost často se
vyskytuje z lenosti programátora, kterému se nechce psát
protected
osobně moc nedoporučuji, protože svazuje přístupová práva s
organizací do balíků (-> a ta se může přece jen měnit častěji než
např. vztah nadtřída-podtřída
.)
Mohlo by mít význam, je-li práce rozdělena na více lidí na jednom balíku pracuje jen jeden člověk - pak si může přátelským přístupem chránit své neveřejné prvky/třídy -> nesmí ovšem nikdo jiný chtít mé třídy rozšiřovat a používat přitom přátelské prvky.
Používá se relativně často pro neveřejné třídy definované v jednom zdrojovém souboru se třídou veřejnou.
private
=> přístupné jen v rámci třídy,
ani v podtřídách - používá se častěji pro proměnné než metody
označením private prvek zneviditelníme i případným podtřídám!
public class Account {
private String owner;
...
}
proměnná owner
je soukromá = nelze k ní
přímo přistoupit ani v podtřídě - je tedy třeba zpřístupnit
proměnnou pro "vnější" potřeby jinak, např.
přístupovými metodami setOwner(String m)
a String getOwner()
Nastavení přístupových práv k třídě pomocí modifikátorů se děje na úrovni tříd, tj. vztahuje se pak na všechny objekty příslušné třídy i na její statické vlastnosti (proměnné, metody) atd.
Nastavení musí vycházet z povahy dotyčné proměnné či metody.
Nevíme-li si rady, jaká práva přidělit, řídíme se následujícím:
metoda by měla být public
, je-li užitečná
i mimo třídu či balík - "navenek"
jinak protected
máme-li záruku, že metoda bude v případných podtřídách
nepotřebná, může být private
- ale
kdy tu záruku máme???
proměnná by měla být private
, nebo
protected
, je-li potřeba přímý přístup v
podtřídě
téměř nikdy bychom neměli deklarovat proměnné jako
public
!
Třídy deklarované jako veřejné
(public
) musí být umístěné do souborů s názvem
totožným s názvem třídy (+přípona .java
) i na
systémech Windows (vč. velikosti písmen)
kromě takové třídy však může být v tomtéž souboru i libovolný počet deklarací neveřejných tříd
private
nemají význam, ale
přátelské ano
Soubor Person.java
bude obsahovat (pozor na
velká/malá písmena - v obsahu i názvu souboru):
public class Person {
... popis vlastností (proměnných, metod...) osoby ...
}
public
značí, že třída je "veřejně"
použitelná, tj. i mimo balík
Balíky obvykle organizujeme do hierarchií, např.:
třídy "dceřinného" balíku (např.
cz.muni.fi.pb162.banking.credit
)
byly zároveň třídami balíku "rodičovského"
(cz.muni.fi.pb162.banking
)!!!
Hierarchie balíků má tedy význam spíše pro srozumitelnost a logické členění.
Deklarujeme ji syntaxí: package
názevbalíku;
Uvádíme obvykle jako první deklaraci v zdrojovém souboru;
Příslušnost k balíku musíme současně potvrdit správným umístěním zdrojového souboru do adresářové struktury;
např. zdrojový soubor třídy Person
umístíme do podadresáře cz\muni\fi\pb162
Neuvedeme-li příslušnost k balíku, stane se třída součástí implicitního balíku - to však nelze pro jakékoli větší a/nebo znovupoužívané třídy či dokonce programy doporučit a zde nebude tolerováno!
import NázevTřídy
Deklarace import nesouvisí s děděním, ale s organizací tříd programu do balíků:
Umožní odkazovat se v rámci kódu jedné třídy na ostatní třídy
Syntaxe: import názevtřídy;
kde názevtřídy je uveden včetně názvu balíku
Píšeme obvykle ihned po deklaraci příslušnosti k balíku
(package názevbalíku;
)
import názevbalíku.*
Pak lze používat všechny třídy z uvedeného balíku
Doporučuje se "import s hvězdičkou" nepoužívat:
jinak nevíme nikdy s jistotou, ze kterého balíku se daná třída použila;
i profesionálové to však někdy používají :-)
lze tolerovat tam, kde používáme z určitého balíku většinu tříd;
v tomto úvodním kurzu většinou tolerovat nebudeme!
"Hvězdičkou" nezpřístupníme třídy z podbalíků, např.
import cz.*
nezpřístupní třídu
cz.muni.fi.pb162.Person