JIHOČESKÁ UNIVERZITA V ČESKÝCH BUDĚJOVICÍCH Pedagogická fakulta Katedra informatiky Akademický rok: 2006/2007
TEZE BAKALÁŘSKÉ PRÁCE
Projekty pro výuku programování v jazyce Java
Jméno: František Přinosil VTI Vedoucí práce: RNDr. Jaroslav Icha
Anotace: Tato práce se zabývá výukou programování v objektově orientovaném programovacím jazyce Java. Práce obsahuje okomentované zdrojové kódy na nichž jsou vysvětleny základy programování. Dále práce obsahuje zadání dílčích projektů sloužících k procvičení popisovaného problému. Řešení těchto projektů je uvedeno v příloze. Klíčová slova: Objektově orientované programování Java Výuka Řešené projekty BlueJ
This thesis deals with the tuition of programming in object oriented programming language Java. It contains source codes with comments which explain the basics of programming. Further on this thesis contains the assigments of several partial projets used for practising the described problem. The solution to this projets is given in the supplement. Key words: Object oriented programming Java Tuition solved projets BlueJ
Úvod V průběhu studia na Pedagogické fakultě mě nejvíce zaujaly předměty týkající se objektově orientovaného programování. Rozhodl jsem se proto zpracovat bakalářskou práci na téma: Projekty pro výuku programování v jazyce Java. Tato bakalářská práce je určena studentům prvního ročníku pedagogické fakulty jako doplňkový materiál ke studiu. A to především studentům dálkového studia. Stejně dobře ji však mohou využít i studenti denního studia jako částečnou náhradu za vynechanou lekci. Pro potřeby výuky jsem zvolil vývojové prostředí BlueJ, které je vyvinuté speciálně pro výuku objektově orientovaného programování v jazyce Java. Práce je rozdělena do několika kapitol. Každá kapitola začíná stručným úvodem, který informuje o znalostech nutných ke studiu dané kapitoly a o dovednostech, které čtenář studiem příslušné kapitoly získá. Dále následuje ukázkový příklad. Příklad se skládá ze zdrojového kódu, který je po částech popsán a vysvětlen. Každý ukázkový příklad si může čtenář stáhnout a vyzkoušet. Následuje série úkolů, při kterých dochází k úpravám či k rozšíření kódu. První kapitola má za úkol seznámit s programovacím jazykem Java a vývojovým prostředím BlueJ, informovat o zdrojích, kde se dají získat potřebné vývojové nástroje, a dále pojednává o způsobu instalace. Druhá kapitola se věnuje základním dovednostem týkajících se programovacího jazyka. Je rozdělena do následujících podkapitol: 1. primitivní typy 2. pole 3. základní řídící konstrukce 4. rozhraní (interface) 5. abstraktní třídy 6. vnitřní třídy
Třetí kapitola pojednává o možnosti využití některých knihoven a o práci s nimi. Je rozdělena na podkapitoly: 1. kolekce (java.util) 2. datové toky (java.io) 3. grafické rozhraní (javax.swing)
Čtvrtá
kapitola
seznamuje
čtenáře
se
orientovaného programování. Dělí se na podkapitoly: 1. objekt, třída 2. dědičnost 3. polymorfismus
základními
principy
objektově
Ukázkový příklad Autorizovaný přístup Nutné znalosti
Pro studium této kapitoly jsou nezbytné znalosti pojmů jako je třída, metoda a atribut. Není nutné pouze tyto pojmy znát, ale také umět s nimi pracovat. Dále jsou zvláště v závěru kapitoly předpokládané základní znalosti týkající se výjimek.
Cíle kapitoly Cílem kapitoly je seznámit čtenáře s možností přístupu k datům zapouzdřených uvnitř třídy pomocí metod. V těchto metodách mohou být na vstupní parametry kladeny další podmínky, které vyplývají z charakteru úlohy. Demonstrační příklady jsou umístěny na internetové stránce http://frp.wz.cz/JWS/ap.php.
Jedním ze základních pilířů objektově orientovaného programování je autorizovaný přístup k datům. Principem je skrytí dat uvnitř instance třídy a jejich zpřístupnění pouze pomocí metod. Nejdříve se pokusím na jednoduchém příkladě demonstrovat, k jakým problémům by mohlo dojít při nepoužívání autorizovaného přístupu. K tomu použiji třídy Zamestnanec a GUI. Třída Zamestnanec bude představovat zaměstnance školy. Každý zaměstnanec bude mít tři atributy. Atribut jmeno bude označovat jméno zaměstnance, obdobně atribut prijmeni. Atribut pocetHodin bude představovat počet hodni odpracovaných zaměstnancem. Dále obsahuje metodu toString(), která poskytuje znakovou reprezentaci objektu. Třída GUI bude představovat formulář(obr 1.), který bude sloužit k zadávání údajů o zaměstnanci a zároveň bude vypisovat informace o vytvořených zaměstnancích do listu.
Obr 1.
Jak vidíte formulář obsahuje tři textová pole pojmenovaná tpJmeno, tpPrijmeni, tpPocetHodin, která jsou určena pro vstup jednotlivých parametrů. Dále obsahuje grafickou komponentu List nazvanou list, která slouží ke zobrazování vytvořených zaměstnanců. Poslední komponentou, o které se budu zmiňovat, je tlačítko uložit nazvané
tlUlozit,
po
jehož
stisknutí
se
vykoná
metoda
public
void
actionPerformed(ActionEvent e). Detailnějším popisem se nebudu zabývat, gui není předmětem této práce. Uvnitř třídy GUI je také vytvořena instance třídy ArrayList, která slouží k uchovávání instancí typu Zamestnanec. private ArrayList
seznamZamestnancu;
Třída Zamestnanec public class Zamestnanec { /** * Proměná představující jméno zaměstnance */ public String jmeno; /** * Proměná představující příjmení zaměstnance */ public String prijmeni; /**
* Proměná představující počet odpracovaných hodin */ public int pocetHodin; /** * Konstruktor pro objekt třídy Zaměstnanec */ public Zamestnanec() { } public String toString() { return jmeno + " " + " " +prijmeni + " " + String.valueOf(pocetHodin); } } Třída GUI public class GUI extends JFrame { JButton tlUloz; /** * Textové pole sloužící pro vstup parametru jmeno. */ JTextField tpJmeno; /** * Textové pole sloužící pro vstup parametru prijmeni. */ JTextField tpPrijmeni; /** * Textové pole sloužící pro vstup parametru pocetDeti. */ JTextField tpPocetDeti; /** * Seznam sloužící k uchovávání instancí typu Zamestnanec. */ private ArrayList seznamZamestnancu; /** * Grafická komponenta sloužící k zobrazování údajů o Zaměstnancích.
*/ JList list; GUI() { … tlUloz.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) {
String jmeno = tpJmeno.getText(); String prijmeni = tpPrijmeni.getText(); int pocetHodin = Integer.valueOf(tpPocetDeti.getText());
Zamestnanec zm = new Zamestnanec(); zm.jmeno = jmeno; zm.prijmeni = prijmeni; zm.pocetHodin = pocetHodin;
seznamZamestnancu.add(zm); li.setListData(seznamZamestnancu.toArray()); } } … public static void main(String[] args) { new GUI().setVisible(true); }
}
Jak
vidíte,
nejzajímavější
je
zde
metoda
public
void
actionPerformed(ActionEvent e). Jsou zde deklarovány tři nové proměnné metody: jmeno, prijmeni a pocetHodin, do kterých jsou ukládány hodnoty z textových polí. Dále zde dochází k vytvoření instance typu Zamestnanec a následně k uložení hodnot z textových polí do příslušných instančních proměnných instance třídy Zamestnanec a to pomocí metody getText(), která vrací objekt typu string. V závěru je nově vytvořený zaměstnanec přidán do seznamu zaměstnanců, jehož obsah je posléze vypsán do listu.
Nyní mohu program spustit a vytvořit svého prvního zaměstnance (obr 2).
Obr 2. Jak vidíte z obrázku, hodnoty, které jsem zadal do textových polí nebyly zvoleny nejvhodněji. Počet odpracovaných hodin je záporný. Jméno a příjmení začíná malým písmenem. Z hlediska kódu je ale vše v pořádku jmeno a prijmeni jsou proměnné typu string a pocetHodin proměnná typu int. Jak zajistit, aby do proměnných jmeno a prijmeni mohly být ukládány pouze hodnoty typu string začínající velkým písmenem a do proměnné pocetHodin pouze nezáporná celá čísla? Použiji následující řešení: Instanční proměnné uvodím klíčovým slovem private, tím znepřístupním tyto proměnné ze všech tříd, kromě třídy Zamestnanec. Pokusíme-li se k některé z těchto privátních proměnných přistoupit z jiné třídy něž je Zamestnanec například voláním zm.jmeno = petr; v metodě void actionPerformed(ActionEvent e) třídy GUI, bude nám ohlášena chyba: „jmeno has private access in Zamestnanec“, již při kompilaci. K těmto privátním proměnným budu přistupovat pomocí veřejných metod, kde mohu klást na vstupní hodnoty další podmínky. Z pravidla se vytvářejí dvě metody pro jednu proměnnou. Jedna z metod, obvykle se její název vytváří z předpony get a jména proměnné, slouží k získání hodnoty proměnné. Druhá metoda, obvykle se její jméno skládá z předpony set a jména proměnné, slouží k uložení hodnoty do proměnné. Samozřejmě z hlediska češtiny tohle
není zcela korektní řešení, ale z hlediska programování se takto vytváří velmi dobře čitelný kód. Právě v metodě, určené pro uložení hodnoty do proměnné instance máme možnost omezit příslušnou podmínkou uložení dané hodnoty. Například metoda pro ukládání hodnoty do proměnné pocetHodin by mohla vypadat následovně:
public void setPocetHodin(int pocetHodin) { if (pocetHodin>=0) this.pocetHodin=pocetHodin; }
Její ekvivalent metoda sloužící pro získání hodnoty uložené v instanční proměnné pocetHodin by mohla vypadat takto:
public int getPocetHodin() { return pocetHodin; }
Obdobným způsobem upravíme i přístup ke zbývajícím instančním proměnným třídy Zamestnanec. public void setJmeno(String jmeno) { if(jmeno.substring(0, 1).equals(jmeno.substring(0,1).toUpperCase())) this.jmeno = jmeno; } public void setPrijmeni(String prijmeni) { if(prijmeni.substring(0, 1).equals(prijmeni.substring(0,1).toUpperCase())) this.prijmeni = prijmeni; } public String getJmeno() { return jmeno; } public String getPrijmeni() { return prijmeni; }
Nyní
ještě
musíme
provést
drobnou
úpravu
v metodě
void
actionPerformed(ActionEvent e) třídy GUI, nemůžeme již přistupovat k proměnným jmeno, prijmeni a pocetHodin přímo, ale musíme použít již vytvořené metody.
zm.setPocetHodin(Integer.valueOf(tpPocetDeti.getText())); zm.setJmeno(tpJmeno.getText()); zm.setPrijmeni(tpPrijmeni.getText());
Nyní můžeme program zpustit a vytvořit si několik zaměstnanců. Použijeme-li hodnoty, které budou vyhovovat námi stanoveným podmínkám, budou tyto hodnoty uloženy do instančních proměnných. V opačném případě zůstane v instančních proměnných uložena jejich implicitní hodnota. Vše ukazuje následující obrázek:
Obr 3.
Neprojde-li hodnota našimi podmínkami, bylo by vhodné na tuto skutečnost upozornit. Například tak, že bude vyvolána výjimka. Nic nám nebrání v tom vytvořit novou výjimku typu IllegalArgumentExceptino a zajistit její vyhození příkazem throw při patřičné situaci. Následující příklad je ukázkou pozměněné metody setPocetHodin, která vyhazuje při zadání záporného počtu hodin příslušnou výjimku. Obdobným způsobem jsou upraveny i metody setJmeno a setPrijmeni.
public void setPocetHodin(int pocetHodin) { if (pocetHodin<0) { throw new IllegalArgumentException("Pocet odpracovaných hodin nemůže být záporné číslo."); } this.pocetHodin=pocetHodin; }
Bude-li nyní pomocí metody setPocetHodin ukládána záporná hodnota, dojde za běhu programu k vyhození výjimky. V opačném případě se uloží hodnota parametru metody do proměnné pocetHodin. K vyhození výjimky může dojít tedy při ukládání hodnot, proto by bylo vhodné uzavřít tyto části kódu do chráněné oblasti. V našem případě budeme odchytávat výjimky v metodě void actionPerformed(ActionEvente) třídy GUI. Odchycení by mohlo vypadat třeba následovně:
try { zm.setJmeno(tpJmeno.getText()); } catch(IllegalArgumentException ex) { System.out.println(ex.toString()); } try { zm.setPrijmeni(tpPrijmeni.getText()); } catch(IllegalArgumentException ex) { System.out.println(ex.toString()); } try { zm.setPocetHodin(Integer.valueOf(tpPocetDeti.getText())); } catch(IllegalArgumentException ex) { System.out.println(ex.toString()); }
Odchycení výjimky a její následující vypsání ukazuje následující obrázek. K výpisu je použito terminálové okno BlueJ.
Obr 4.
Jak je z obrázku patrné, byla vytvořena instance třídy Zamestnanec, v jejich instančních proměnných jmeno a prijmeni je uložena implicitní hodnota, zadávané hodnoty nevyhovovali požadavkům, nebyly uloženy a byly tudíž vyvolány příslušné výjimky.
Pokud bychom požadovali, aby instance třídy v případě zadání špatných parametrů vůbec nebyla vytvořena, museli bychom provádět kontrolu parametrů již v konstruktoru. Z toho vyplývá nutnost použití konstruktoru z parametry.
public Zamestnanec(String jmeno, String prijmeni, int pocetHodin) { if (!(jmeno.substring(0, 1).equals(jmeno.substring(0,1).toUpperCase()))) { throw new IllegalArgumentException("Jmeno zaměstnance nemůže začínat malým písmenem."); } …
Z uvedeného kódu je patrná jistá duplicita, vždyť podobné ověření se provádí v metodách setJmeno, … Nebylo by vhodnější inicializovat instanční proměnné již v konstruktoru pomocí přístupových metod a tím se vyhnout duplicitnímu a složitému kódu? Konstruktor by pak vypadal následovně:
public Zamestnanec(String jmeno, String prijmeni, int pocetHodin) { setJmeno(jmeno); setPrijmeni(prijmeni); setPocetHodin(pocetHodin); }
Nyní při vytváření instance třídy Zamestnanec může být vyhozena výjimka. Na tuto skutečnost musíme ještě reagovat drobnou úpravou v kódu třídy GUI.
try { Zamestnanec zm = new Zamestnanec(jmeno, prijmeni, pocetHodin); seznamZamestnancu.add(zm); } catch (IllegalArgumentException ex) { System.out.println(ex.toString()); }
Nyní při zadání nekorektních parametrů nebude instance třídy Zamestnance vytvořena a bude vyhozena příslušná výjimka. Vše ukazuje následující obrázek:
Obr 5.
Co je již hotovo, co plánuji udělat Kompletně zpracovaná čtvrtá kapitola týkající se základních principů objektově orientovaného programování (35 stran). Dále je z velké části vytvořena druhá kapitola chybějí pouze ukázkové příklady k podkapitolám abstraktní a vnitřní třídy. V třetí kapitole je ke každé podkapitole vytvořeno několik příkladů. Výběr demonstračního příkladu ještě zvažuji. Práci bych ještě rád doplnil o vhodné animace, které umožní lepší proniknutí do některých problémů. Zvláště vhodné se mi jeví u podkapitol týkajících se řídících konstrukcí, a to jak podmínkových příkazů tak u cyklů. V současné době vedu kroužek programování v jazyce Java na Střední škole podnikání. Tato aktivita mi umožňuje získat zpětnou vazbu o mé práci. Tyto informace bych rád použil jako vodítko pří výběru vhodnosti ukázkových projektů.
Seznam odborné literatury: David J. Barnes, Michael Kölling. Objects First With Java, second edition. Pearson Education Limited, 2005. Rudolf Pecinovský. Myslíme objektově v jazyku Java 5. Grada Publishing, a.s., 2004.
Závěr Vzhledem k tomu, že práce detailně popisuje uvedená témata a snaží se přímým způsobem seznámit čtenáře se základními dovednostmi při programování v jazyce Java, může být využíván pro potřeby studentů JU. A to jak pro studenty prezenčního studia k zopakování či ujasnění látky, tak i pro studenty kombinovaného studia. Z těchto potřeb je připravena i elektronická verze práce ve formě webové prezentace.