Obsah 6. přednášky: Třídy a objekty Deklarace třídy a objektu, vytvoření objektu Proměnné primitivní vs. objektové Přímý přístup k atributům a metodám Program sestávající z více tříd Konstruktor a klíčové slovo this Autorizovaný přístup Vytváření, volání a přetěžování metod Pole objektů třídy String - příklad knihovní třídy Metody třídy String a jejich použití Třída StringBuffer* Programování procedurální vs. objektové Tato tematika je zpracována v Záznamy přednášek: str. 123 152 Prostudujte i motivační příklad Osoba - BMI! Budete ho potřebovat na cvičení a při řešení domácích úloh. Přednášky KIV/PPA1, A. Netrvalová, 2016 6. přednáška
Třídy a objekty Programování - procedurální (dosud) - objektové (OOP objektově orientované programování) Motivace vzniku OOP Dekompozice problému s velkým množstvím detailů na dílčí zvládnutelné problémy, s možností řešení současně více programátory Simula 67 (1967, Norwegian Computing Center) základem byl Algol 60 (bloková struktura) Blok (podprogram), nezávislý na zbytku programu - formální popis vzor seskupení dat, algoritmů a akcí - vykonání - vytvoření dynamické instance Java třída jako nový datový typ Třída (class) - základní jazyková konstrukce OOP - šablona (template) objektový typ, pro dynamické vytváření objektů této třídy - členské /instanční proměnné /atributy (stav) - členské /instanční metody (chování) Strana 2 (celkem 37)
Příklad: třída Kruh Kruh o poloměru r s výpočtem plochy P Kruh r double polomer P = r 2 double spoctiplochu() Objekt (object), instance (instance) - datový prvek (množina hodnot a množina operací), vytvořený dle vzoru třídy Příklad objektů třídy Kruh r = 1 1 P = 3.14 mujkruhzluty r = 2 mujkruhmodry polomer = 1.0 P = 12.56 polomer = 2.0 P = 3.14 P = 12.56 Strana 3 (celkem 37)
Deklarace třídy a objektu, vytvoření objektu Deklarace třídy Příklad: class Jmeno { typ a jmeno atributu, inicializace typ a jmeno metody() {... telo metody... class Kruh { double polomer = 1.0; double spoctiplochu() { return 3.14*polomer*polomer; Deklarace a vytvoření objektu Přístup k objektům - prostřednictvím referenční proměnné např. mujkruhzluty, mujkruhmodry Strana 4 (celkem 37)
Deklarace objektu JmenoTridy jmenoobjektu; Příklad: Kruh mujkruh; referenční proměnná mujkruh null Vytvoření objektu jmenoobjektu = new JmenoTridy(); Příklad: mujkruh = new Kruh(); referenční proměnná mujkruh Kruh polomer = 1 objekt Strana 5 (celkem 37)
Deklarace a vytvoření objektu současně JmenoTridy jmenoobjektu = new JmenoTridy(); Příklad: Kruh mujkruh = new Kruh(); Zrušení objektu (Garbage collector) - pokud na objekt není reference Příklad: mujkruh = null; referenční proměnná mujkruh null Kruh polomer = 1 objekt Strana 6 (celkem 37)
Proměnné primitivní vs. objektové Rozdíl v pojetí - při deklaraci a vzniku Primitivní typ při deklaraci při vytvoření Objektový typ při deklaraci k int i; i = 1; i i??? Kruh k = new Kruh(); null 1 při vytvoření k Kruh polomer = 1 - při přiřazení proměnných int i = 1; Kruh k1 = new Kruh(5); int j = 2; Kruh k2 = new Kruh(9); Přiřazení: primitivní typ i = j před: po: Přiřazení: typ objekt k1 = k2 před: po: i 1 i 2 k1 k1 j 2 j 2 k2 k2 Kruh Kruh polomer = 5 polomer = 9 Strana 7 (celkem 37)
Přímý přístup k objektu tj. k atributům a metodám Reference atributu či metody - tečkovaná notace Komunikace s objektem - zasíláním zpráv (volání instančních metod) Reference atributu jmenoobjektu.promenna Př.: mujkruh.polomer Reference metody jmenoobjektu.metoda() Př.: mujkruh.spoctiplochu() Program sestávající z více tříd Deklaraci, vytvoření a použití objektu (tj. atributů a metod) provádíme v jiné třídě. Na počátku, pro jednoduchost, budeme vytvářet a používat programy sestávající pouze ze dvou tříd. Hlavní program - tj. třída obsahující main() - zde budeme programy spouštět. Pokud program sestává z více tříd, každou třídu ukládáme do samostatného souboru (výjimkou je odevzdání DÚ na validátor). Důvodem je snadné použití třídy v jiném programu či předání třídy (souboru) jinému programátorovi. Strana 8 (celkem 37)
Poznámky: Uložení programu - pokud jsou třídy výjimečně uloženy společně v jednom souboru, potom je pouze třída s hlavním programem, tj. s metodou main(), opatřena modifikátorem public! Překlad programu třída: - příkazová řádka: javac JmenoTridy.java - Scite: Ctrl+F7 celý program: - příkazová řádka: javac *.java - Scite: F7 Spouštění programu třída: - příkazová řádka: java JmenoTridy - Scite: F5 celý program: - příkazová řádka: java HlavniProgram - Scite: F5 v hlavní třídě Terminologie - poznámka - pro označení třídy jakožto šablony se lze setkat s pojmem datová třída (Data Model Class), tj. třída sloužící zejména k uchování dat a manipulaci s nimi. Instancí takové třídy je datový objekt (Data Object). Strana 9 (celkem 37)
Příklad vytvoření a použití objektu class Kruh { TŘÍDA KRUH double polomer = 1.0; double spoctiplochu(){ return 3.14*polomer*polomer; public class TestKruhu { HLAVNÍ PROGRAM TŘÍDA - obsahující main() (ŘÍDICÍ, APLIKAČNÍ, UŽIVATELSKÁ) public static void main(string[] args){ // main()-entry point Kruh mujkruh = new Kruh(); // vytvoreni //polomer nastaven na inicializovanou hodnotu atributu tridy System.out.println("Polomer = " + mujkruh.polomer); mujkruh.polomer = 10;// nastaveni nove hodnoty polomeru // vypis System.out.println("Plocha kruhu o polomeru " + mujkruh.polomer + " je " + mujkruh.spoctiplochu() + "."); Polomer = 1.0 Plocha kruhu o polomeru 10.0 je 314.1592653589793. Výpis výsledků v předchozím příkladu je zbytečně zdlouhavý, a kdykoliv budeme potřebovat vypsat poloměr či plochu musíme příkazy zopakovat. Strana 10 (celkem 37)
Řešením je použití metody String tostring(), (vrací řetězec se stavem objektu), napíšeme ji dle potřeby ve třídě Kruh a pak tuto metodu zavoláme (v metodě pro výpis) v hlavním programu (viz dále). class Kruh { public class TestKruhu { double polomer = 1.0; double spoctiplochu(){ return 3.14*polomer*polomer; /** Vypis objektu pouzitim metody tostring() (pretizena metoda) * @return String retezec s informaci o objektu */ public String tostring(){ return "<Kruh: polomer = " + polomer + ", plocha = " + spoctiplochu() + ">"; public static void main(string[] args){ Kruh mujkruh = new Kruh(); System.out.println("Polomer = " + mujkruh.polomer); mujkruh.polomer = 10; // vhodnejsi zpusob vypisu System.out.println(mujKruh.toString()); // staci pouze zapis bez uvedeni tostring() System.out.println(mujKruh); Strana 11 (celkem 37)
Konstruktor a klíčové slovo this Konstruktor - speciální metoda, která umožňuje vytvoření objektu (přidělení paměti a inicializace členských proměnných) Liší se od ostatních metod: - nelze volit jeho jméno, má jméno třídy - nemá žádnou návratovou hodnotu (tj. ani void) - nelze volat rekurzivně - použití operátoru new Konstruktor - implicitní vytvoří se, i když ho nenapíšeme (předchozí příklad fungoval! Volali jsme Kruh(), ale ve třídě Kruh konstruktor zapsán nebyl) - explicitní nutno napsat (může být i přetížen, tj. konstruktorů můžeme napsat více) Použití klíčového slova this - typicky se vyskytuje v konstruktoru, ale i jinde (viz dále) Formální parametry konstruktoru mají často jméno shodné s atributem nutno odlišit. Řešením je this.jmenoatributu neboť this odkazuje vždy na samotný objekt. Upravíme tedy náš předchozí příklad: Strana 12 (celkem 37)
public class Kruh { double polomer; Kruh(double polomer) { // konstruktor this.polomer = polomer; // this zde musí byt Kruh(){ /* konstruktor bez parametru, musi byt napsan, ale jen pokud jej potrebujeme, tzv. pretizeny konstruktor */ polomer = 1.0; // this zde neni nutné, nelze pochybit double spoctiplochu(){ return polomer*polomer*math.pi; // this by mohlo byt uvedeno, ale zatim nadbytecne... public class TestKruhuSKonstruktory { //aplikace public static void main(string[] args) { // nastav polomer 5.0 Kruh mujkruh = new Kruh(5.0); // vypocet a tisk System.out.println(mujKruh); // defaultni polomer Kruh tvujkruh = new Kruh(); // vypocet a tisk System.out.println(tvujKruh); <Kruh: polomer = 5.0, plocha = 78.53981633974483> <Kruh: polomer = 1.0, plocha = 3.141592653589793> Strana 13 (celkem 37)
Autorizovaný přístup Uživatel se pohodlně dostává přímým přístupem k nastavení atributu - výhoda, ale tím pádem může tento atribut i nevhodně změnit - nevýhoda (např. v našem případě zadat záporný poloměr!) Řešení - použít modifikátor (specifikátor) private (privátní, soukromý) - zapouzdření (encapsulation) skrytí atributů před vnějšími vlivy Přístupová práva: Specifikátor public private protected žádný (tzv. package friendly) Z libovolné třídy. Povolený přístup Pouze zevnitř dané třídy, žádný přístup z vnějšku. Z kterékoliv třídy téhož balíku, případně z potomka třídy kdekoliv. Z kterékoliv třídy téhož balíku. Důsledek - použitím specifikátoru private přímý přístup k atributu již nefunguje! Nutný autorizovaný přístup, tj. - vytvoření přístupových metod pro nastavení a vrácení hodnoty atributu (setters, getters) Poznámka: Přístupové právo metod bývá většinou public, ale i metody je možné (někdy vhodné) skrývat, potom je použit modifikátor private (s důsledky obdobnými jako u atributu). Strana 14 (celkem 37)
Úprava: přidáme modifikátor private pro atribut polomer a přístupové metody getpolomer() a setpolomer() public class Kruh { private double polomer; // privatni atribut public Kruh() { polomer = 1.0; public Kruh(double polomer) { setpolomer(polomer); // volani setru v konstruktoru // metoda pristupu k atributu vraceni hodnoty = getr public double getpolomer() { return polomer; // metoda pristupu k atributu nastaveni hodnoty = setr public void setpolomer(double polomer) { if(polomer > 0){ this.polomer = polomer; //osetri pripustnost vstupu double spoctiplochu(){ return polomer*polomer*math.pi; public String tostring(){ return "<Kruh: polomer = " + polomer + ", plocha = " + spoctiplochu() + ">"; Strana 15 (celkem 37)
public class TestKruhuSPrivateModifikatorem { public static void main(string[] args) { // Vytvor kruh a nastav polomer 5.0 Kruh mujkruh = new Kruh(5.0); /* Toto uz nelze pouzit!!! System.out.println(mujKruh.polomer); */ // vypocet a tisk System.out.println(mujKruh); // Zvetsi polomer o 10% mujkruh.setpolomer(mujkruh.getpolomer()*1.1); System.out.println(mujKruh); <Kruh: polomer = 5.0, plocha = 78.53981633974483> <Kruh: polomer = 5.5, plocha = 95.03317777109125> Vytváření, volání, přetěžování metod Vytváření - píšeme dle běžných konvencí - instanční metody - static ne! (instance je dynamická) Volání - z aplikační třídy (použít referenci na objekt, který metodu volá!) - v rámci stejné třídy (běžné konvence) Přetěžování - platí stejná pravidla jako pro statické metody Strana 16 (celkem 37)
Pole objektů třídy - větší počet objektů: soubor položek stejného typu - vhodné použít pole (jako dříve) Motivační příklad stene objekt Pes objekt Pes Lord Rex objekt Pes Lady null null 0 1 2 3 4 $ smecka pole referencí na objekty Pes Pes stene = new Pes ("Rex"); Pes [] smecka = { new Pes("Lord", stene, new Pes ("Lady") ; Vytvořeny 3 objekty: Pes - objekt referencovaný jako stene a smecka[1] Pes - objekt referencovaný jako smecka[0] Pes - objekt referencovaný jako smecka[2] Pes[] - pole objektů referencované jako smecka Strana 17 (celkem 37)
Úprava příkladu Kruh (aplikační třídy TestKruhu.java): Úkol - vytvořme několik objektů typu Kruh a seřaďme je podle velikosti ploch Řadíme reference nikoliv objekty! Upravovat budeme pouze aplikační třídu, do které doplníme mimo jiné i metodu řazení. Přidáme statickou metodu pro vytvoření pole objektů Kruh a statickou metodu řazení podle velikosti plochy, zvolíme metodu InsertSort, kterou upravíme pro řazení objektů. Pozor: Porovnávání při řazení nutno použít reference na atribut či metodu! Všimněte si příkazu: p = tmp.spoctiplochu(); výpočet p odstraní několikanásobné použití reference metody (a tudíž počítání hodnoty, která se nemění) v cyklu while! Výstup programu z následující stránky: [<Kruh: polomer = 3.0, plocha = 28.274333882308138>, <Kruh: polomer = 2.0, plocha = 12.566370614359172>, <Kruh: polomer = 3.0, plocha = 28.274333882308138> ] [<Kruh: polomer = 2.0, plocha = 12.566370614359172>, <Kruh: polomer = 3.0, plocha = 28.274333882308138>, <Kruh: polomer = 3.0, plocha = 28.274333882308138> ] Strana 18 (celkem 37)
import java.util.*; public class TestKruhuPoleObjektu { static private Random r = new Random(); public static Kruh[] vytvorkruhy(int pocetkruhu){ Kruh [] kruhy = new Kruh [pocetkruhu]; for(int i=0;i<kruhy.length;i++){ kruhy[i] = new Kruh(r.nextInt(pocetKruhu)+1); return kruhy; public static void seradpodleplochy(kruh kruhy[]) { for (int i=0; i<kruhy.length; i++) { Kruh tmp = kruhy[i]; int j=i; double p = tmp.spoctiplochu(); while((j>0) && (kruhy[j-1].spoctiplochu() > p)) { kruhy[j]=kruhy[j-1]; j--; kruhy[j]=tmp; public static void main(string[] args) { int pocetkruhu = r.nextint(5)+1; Kruh [] kruhy = vytvorkruhy(pocetkruhu); System.out.println(Arrays.toString(kruhy)); seradpodleplochy(kruhy); System.out.println(Arrays.toString(kruhy)); Strana 19 (celkem 37)
Příklad: náš první program Pozdrav - objektově public class HelloWorld { public static void main(string[] args) { Pozdrav pozdrav = new Pozdrav("Ahoj světe!"); pozdrav.print(); // 1. zpusob System.out.println(pozdrav); // 2. zpusob // nyni se pozdrav zmeni, puvodni je uz nedostupny pozdrav = new Pozdrav("Hello world!"); pozdrav.print(); System.out.println(pozdrav); class Pozdrav { private String text; public Pozdrav(String pozdrav) { text = pozdrav; // privatni metoda - privatni getr private String gettext() { // zde private ok return text; // 1 - metoda pro vypis // konstruktor Ahoj světe! Ahoj světe! Hello world! Hello world! public void print() { // public metoda vola privatni getr System.out.println(getText()); // 2 - metoda pro vypis public String tostring(){ // public metoda vola privatni getr return gettext(); Poznámka pro odevzdávání DÚ na validátor: Validátor pracuje pouze s jedním souborem. Takže, kdybychom chtěli např. odevzdat předchozí příklad, pak třídu Pozdrav uvedeme bez specifikátoru public a uložíme spolu do souboru s HelloWorld (v tomto souboru tedy budou dvě třídy). Pouze aplikační třída může mít specifikátor public. Takto upravený výsledný soubor odešleme na validátor. Strana 20 (celkem 37)
Poznámka (podrobně - viz Záznamy - str. 127): Na cvičení a v DÚ bude používán lékařský termín BMI (Body Mass Index), který nemá nic společného s programováním. Je pouze použit pouze pro příklad výpočtu dat odvozených z dat základních. BMI: podíl hmotnosti [kg] a čtverce výšky [m], tj. Hodnoty BMI: BMI = m / (v * v) < 18 podváha 18 až 25 ideální hmotnost 25 až 30 nadváha > 30 obezita ohrožující zdraví Příklad: vytvoříme třídu Osoba s atributy jmeno, vaha, vyska s konstruktorem Osoba() s metodami: getjmeno(), getvaha(), setvaha(), getvyska() a vypoctibmi() (viz slide na následující stránce) Dále si vytvoříme v aplikační třídě objekt třídy Osoba, tj. osobu Hana, s vahou 50 kg a výškou 170 cm. Vypíšeme informace o objektu, jméno a spočtené BMI. Potom nastavíme váhu Hany na 55 kg a opět objekt (tj. informace o něm) vypíšeme. public class OsobyObjektyAplikace { public static void main(string[] args) { Osoba o; o = new Osoba("Hana", 50, 170); System.out.println(o.toString()); System.out.println(o.getJmeno() + " ma BMI " + o.vypoctibmi()); o.setvaha(55.0); System.out.println(o); <Hana, vaha: 50.0, vyska: 170, BMI: 17> Hana ma BMI 17 <Hana, vaha: 55.0, vyska: 170, BMI: 19> Strana 21 (celkem 37)
class Osoba { private String jmeno; // atributy private double vaha; private int vyska; // konstruktor public Osoba(String jmeno, double vaha, int vyska) { this.jmeno = jmeno; setvaha(vaha); this.vyska = vyska; // getry a setry public String getjmeno() { return jmeno; public double getvaha() { return vaha; public void setvaha(double vaha) { if (vaha > 0.0) { this.vaha = vaha; public int getvyska() { return vyska; // ostatni metody public int vypoctibmi() { double vyskametry = vyska / 100.0; double bmi = vaha / (vyskametry * vyskametry); return (int) Math.round(bmi); // zaokrouhleni public String tostring() { return "\n<" + jmeno + ", vaha: " + vaha + ", vyska: " + vyska + ", BMI: " + vypoctibmi() + ">"; Strana 22 (celkem 37)
String - příklad knihovní třídy - jedna z nejpoužívanějších tříd (cca 50 metod) - inicializovaný objekt typu String: deklarace proměnné typu String a přiřazení řetězce v uvozovkách (i bez operátoru new) - řetězcový literál (v uvozovkách) - automatické vytvoření objektu typu String // s2 odkazuje na stejny objekt jako s1 // takto budeme prednostne pouzivat String s1 = "retezec"; String s2 = s1; // skutecne vytvoreni noveho objektu, na nejz odkazuje s3 String s3 = new String(s1); System.out.println("s1: " + s1); - řetězec je speciální pole znaků, 0 až length()-1 - jednou vytvořený řetězec je konstantní, nelze jej měnit ( měnitelný řetězec - třída StringBuffer) - spojení řetězců (konkatenace) použitím operátoru + - řetězec jako operand následovaný operandem jiného typu se automaticky převede na řetězec Volání metod a práce s řetězci String s = "ahoj", s1 = "hi", s2 = "bye"; s.jmenometody(), s1.jmenometody(s2) s1: retezec s2: retezec s3: retezec Např.: String s = "Ahoj"; char c = s.charat(0); // A = znak na pozici 0 Strana 23 (celkem 37)
Práce se znaky String s = "Ahoj"; int i = s.length(); // pocet znaku retezce vysledek i=4 int j = s.indexof('a'); // první výskyt znaku 'a' int k = s.lastindexof('o'); // index posledního výskytu 'o' Porovnávání řetězců Příklad: totožnost - výsledek true/false String s1 = "Ahoj"; String s2 = "ahoj"; boolean shoda = s1.equals(s2); // false Příklad: hodnotou - výsledek (0: rovnost, <0: první je menší, >0: druhé je menší) String s1 = "Ahoj"; String s2 = "ahoj"; int k = s1.compareto(s2); // <0 Práce s podřetězci String s = "proto"; int i = s.indexof("to"); // výsledek i= 3 String p = s.substring(2); // výsledek p="oto" Test začátku a konce řetězce String s = "proto"; boolean z = s.startswith("pr"); // výsledek z = true boolean k = s.endswith(''ale"); // výsledek z = false Strana 24 (celkem 37)
Náhrada všech určených znaků String s2,s1 = "cacao"; s2 = s1.replace('c', 'k'); // vysledek kakao Oříznutí bílých znaků String s = "\t ahoj \t\n\r"; s = s.trim(); // ahoj Spojení řetězců (konkatenace) String s1 = "Pan"; String s2 = "TAU"; // operatorem + String s3 = s1 + " " + s2; // metodou concat() String s4 = s1.concat(" " + s2); // Pan TAU Převod řetězce na pole znaků a zpět String s1 = "retezec"; char poleznaku[] = s1.tochararray(); // pouziti pretizeneho konstruktoru String s2 = new String(poleznaku); KONVERZE: A. Řetězec základní datové typy Datové typy int, double, long,... mají své obalovací třídy: Integer, Double, Long,... Strana 25 (celkem 37)
1. Metoda parse() volána ve tvaru: ObalovaciTrida.parseTyp (s) s je String Integer.parseInt(s), Long.parseLong(s), Double.parseDouble(s) 2. Metoda valueof() volána ve tvaru: ObalovaciTrida.valueOf (s) s je String Integer.valueOf(s), Long.valueOf(s), Double.valueOf(s) // Prevod retezce na celociselny typ // 1. zpusob String s1 = "123"; int i = Integer.parseInt(s1); // i = 123 // 2. zpusob String s2 = "123.45"; double p = Double.valueOf(s2) ; // p = 123.45 B. Základní datové typy řetězec 1. Metoda tostring() volána ve tvaru: ObalovaciTrida.toString (x) x je primitivní datový typ Integer.toString(), Long.toString(), Double.toString(), 2. Metoda valueof() volána ve tvaru: String.valueOf(x) x je primitivní datový typ String.tvalueOf(x), Strana 26 (celkem 37)
// Prevod celociselneho typu na retezec // 1. zpusob int i = 123; String s3 = Integer.toString(i); // s3 = "123" // 2. zpusob double p = 123.45; String s4 = String.valueOf(p) ; // s4 = "123.45" Další užitečné metody a třídy pro práci s řetězci o metoda split(), třída StringTokenizer Podrobné informace - JavaCoreAPI (String) Příklad 1: Zpracování dat na vstupu (ilustrace použití třídy String a metod: trim(), split(), parseint()) Na vstupu je neznámý počet dvojic čísel, každá dvojice na jednom řádku, čísla navzájem oddělena mezerou, úkolem je postupné načtení zpracování. String input; String [] idata = new String[2]; // použije split() int a, b; while (sc.hasnext()) { input = sc.nextline().trim(); idata = input.split(" "); a = Integer.parseInt(idata[0]); b = Integer.parseInt(idata[1]); // oddelovac 1 mezera Strana 27 (celkem 37)
Příklad 2: Zjistěte, zda se zadané písmeno v řetězci vyskytuje, a pokud ano, pak na které pozici je jeho první výskyt, pokud ne, pouze vypište zprávu. import java.util.scanner; public class HledaniPismenaVRetezci { private static Scanner sc = new Scanner(System.in); public static void main(string[] args) { System.out.print("Zadejte retezec:"); String retezec = sc.nextline(); System.out.print("Zadejte hledane pismeno:"); char hledej = sc.nextline().charat(0); boolean nalezeno = false; int index = 0; // nasledujici programovou sekvenci bychom museli napsat /* for(int i = 0; i < retezec.length(); i++) { // cyklem if(retezec.charat(i) == hledej){ nalezeno = true; index = i+1; break; */ if((index = retezec.indexof(hledej))>=0) { // knihovni metodou index++; nalezeno = true; if(nalezeno) { System.out.println("Pismeno '"+ hledej + "' je na pozici:" + index); else { System.out.println("Pismeno '"+ hledej + "' nenalezeno!"); Zadejte retezec:alenka Zadejte retezec:alenka Zadejte hledane pismeno:a Zadejte hledane pismeno:o Pismeno 'a' je na pozici:1 Pismeno 'o' nenalezeno! Strana 28 (celkem 37)
Př. 3: Césarova šifra - vytvořte program pro šifrování textu (pouze malá písmena anglické abecedy), které spočívá v posouvání znaku v abecedě o určitý, pevně stanovený počet znaků. Např. slovo "ahoj" se posunem textu o 1 znak transformuje na "bipk". import java.util.*; public class CesarovaSifra { private static Scanner sc = new Scanner(System.in); public static void main(string [] args){ // inicializace promennych String s = "abcdefghijklmnopqrstuvwxyz"; System.out.printf("Puvodni zprava: %s\n", s); String zprava = ""; int posun = 1; // posun mozno nastavit: sc.nextint(); // cyklus prochazejici jednotlive znaky for (char c : s.tochararray()) { // for Each int i = (int)c; i += posun; // presun na zacatek abecedy if (i > (int)'z') { i -= 26; //pocet pismen char znak = (char)i; zprava += znak; // vypis System.out.printf("Zasifrovana zprava: %s\n", zprava); Puvodni zprava: abcdefghijklmnopqrstuvwxyz Zasifrovana zprava: bcdefghijklmnopqrstuvwxyza Další podobnou úložku hledejte na konci přednášky Strana 29 (celkem 37)
Jednoduchý příklad: použití String a objektu - pro připomenutí základů objektového programování Třída DomaciZvirata obsahující: - dvě proměnné: druh zvířete a zvuk, který vydává - dva konstruktory - žádnou metodu public class AplikaceDomaciZvirata { public static void main(string[] args) { // deklarace s inicializaci: instance pes DomaciZvirata alik = new DomaciZvirata(); alik.druh = "pes"; alik.zvuk = "haf"; // vytvorime novou instanci zvirete: kocku DomaciZvirata mica = new DomaciZvirata("kocka","mnau"); System.out.println("Jsem " + alik.druh + " a delam " + alik.zvuk); System.out.println("Jsem " + mica.druh + " a delam " + mica.zvuk); DomaciZvirata pipina = new DomaciZvirata("slepice","kokodak"); System.out.println("Ja jsem " + pipina.druh + " a delam " + pipina.zvuk); // ukazka NullPointerException, odkomentujte nasledujici radek // pipina = null; // objekt nevytvoren System.out.println("" + pipina.zvuk.concat(", kokodak") + " :to je " + pipina.druh); class DomaciZvirata { // druh a zvuk, ktery zvire vydava public String druh; public String zvuk; public DomaciZvirata() { //konstruktor public DomaciZvirata(String druh, String zvuk) { // konstruktor this.druh = druh; this.zvuk = zvuk; Jsem pes a delam haf Jsem kocka a delam mnau Jsem slepice a delam kokodak kokodak, kokodak :to je slepice Strana 30 (celkem 37)
A lépe: třídu DomaciZvirata doplníme metodami kdoje() a jakdela() a metodou tostring() class DomaciZvirata { // doplneni metod public String druh; public String zvuk; public DomaciZvirata(){ public DomaciZvirata(String druh, String zvuk){ this.druh = druh; this.zvuk = zvuk; public String jakdela(){ return zvuk; public String kdoje(){ return druh; public String tostring(){ return "<zvire: " + kdoje() + "... " + jakdela() + ">"; public class AplikaceKockaAPes { public static void main(string[] args) { DomaciZvirata alik = new DomaciZvirata(); alik.druh = "pes"; alik.zvuk = "haf"; DomaciZvirata mica = new DomaciZvirata("kocka","mnau"); // použiti doplnene metody System.out.println("zvire: " + alik.kdoje() + "... " + alik.jakdela()); System.out.println("zvire: " + mica.kdoje() + "... " + mica.jakdela()); DomaciZvirata pipina = new DomaciZvirata("slepice","kokodak"); // zjednoduseni vypisu pouzitim metody tostring() System.out.println(pipina); Strana 31 (celkem 37)
Třída StringBuffer* (pouze informace) - objekty typu String jsou řetězce neměnitelné - vyšší odolnost vůči chybám a efektivnější zacházení - měnitelné řetězce - použít instance třídy StringBuffer. - doporučení - používat instance třídy String, je-li třeba změny - zkonvertovat na typ StringBuffer a pak opět uchovat v objektech typu String. // vytvoreni objektu StringBuffer (s kapacitou 16 znaku) StringBuffer jmenobuf2 = new StringBuffer(); String jmeno = "princezna Lada"; // vytvoreni objektu StringBuffer s pouzitim tridy String StringBuffer jmenobuf1 = new StringBuffer(jmeno); // vytvoreni objektu StringBuffer s kapacitou zadanou cislem StringBuffer jmenobuf2 = new StringBuffer(20); Převod objektu StringBuffer na String a zpět Převod StringBuffer na String se provede metodou tostring. Převod ze String na StringBuffer se provede vhodným použitím operátoru new (je to zcela intuitivní). Ze String do StringBuffer: StringBuffer jmenobuf = new StringBuffer("Pepa "); Ze StringBuffer do String String jmeno = jmenobuf.tostring(); Základy práce s třídou StringBuffer append(), insert ()- přidávání a vkládání textu StringBuffer buf = new StringBuffer("jmeno :"); buf.append(" Koza"); buf.insert(8, " Oliver") // vystup: "jmeno : Oliver Koza"; System.out.println(buf.toString()); Strana 32 (celkem 37)
replace() - změna textu ve StringBufferu StringBuffer buf = new StringBuffer("Miroslav Koula"); String s1 = "Mirek"; // nahradi text zacinajici na pozici 1 až 8 novym textem buf.replace(1,8,s1); capacity() - zjištění kapacity StringBufferu. Kapacita představuje maximalní počet znaků, který lze do StringBufferu uložit. StringBuffer buf = new StringBuffer("delsi retezec"); // delka je nastavena na 10 buf.setlength(10); // ale do kapacity je ulozena hodnota 14 int kapacita = buf.capacity(); reverse() - obrácení textu ve StringBufferu StringBuffer obraceni = new StringBuffer("Radar"); System.out.println("Obraceni Radar: " + obraceni.reverse()); Užitečné testování znaků Character.isDigit()- je znak číslice? Character.isLetter()- je znak písmeno? Character.isLetterOrDigit()- je znak písmeno nebo číslice? Character.isLowerCase()- je znak malé písmeno? Character.isUpperCase()- je znak velké písmeno? Character.isWhitespace()- je to bílý znak? Strana 33 (celkem 37)
StringBuffer s = new StringBuffer(koniklec); System.out.println("Character.isDigit(s.charAt(0)): " + Character.isDigit(s.charAt(0))); System.out.println("Character.isLetter: " + Character.isLetter(s.charAt(0))); System.out.println("Character.isLetterOrDigit: " + Character.isLetterOrDigit(s.charAt(0))); System.out.println("Character.isLowerCase: " + Character.isLowerCase(s.charAt(0))); System.out.println("Character.isUpperCase: " + Character.isUpperCase(s.charAt(0))); System.out.println("Character.isWhitespace: " + Character.isWhitespace(s.charAt(0))); Programování procedurální vs. objektové V následujícím příkladu je patrný rozdíl mezi procedurálním a objektovým programováním. Obě formy mají své výhody a nevýhody! Objektové programování představuje více administrativy, kód je však strukturovaný a přehledný, provedení ale zabere relativně více času. Procedurální programování míchá data a metody, je méně přehledné, ale má relativně rychlejší běh. (více v PPA2) Příklad (Kruh) ilustrace obou forem programování Vytvoříme dva kruhy a napíšeme další metodu, která spočte rozdíl ploch obou kruhů. Strana 34 (celkem 37)
Procedurálně: Počítáme rozdíl dvou ploch. public class SpoctiRozdilPlochProc { static double spoctiplochu(double polomer){ return polomer*polomer*math.pi; static double spoctirozdilploch(double polomer1, double polomer2){ return Math.abs(spoctiPlochu(polomer1)-spoctiPlochu(polomer2)); public static void main(string[] args) { double polomer1 = 10.0; double polomer2 = 1; System.out.println(spoctiPlochu(polomer1)); System.out.println(spoctiPlochu(polomer2)); System.out.println("Rozdil ploch: " + spoctirozdilploch (polomer1, polomer2)); 314.1592653589793 3.141592653589793 Rozdil ploch: 311.01767270538954 Objektově: Počítáme rozdíl plochy kruhu referencovaného, tj. našeho (this) objektu - vůči ploše kruhu jiného objektu, který je předán skutečným parametrem v metodě. Strana 35 (celkem 37)
class Kruh { private double polomer; public Kruh() { polomer = 1.0; public Kruh(double polomer) { setpolomer(polomer); public double getpolomer() { return polomer; public void setpolomer(double polomer) { if(polomer > 0){ this.polomer = polomer; public double spoctiplochu(){ return polomer*polomer*math.pi; public double spoctirozdilploch(kruh k) { return Math.abs(this.spoctiPlochu() - k.spoctiplochu()); public String tostring() { return "<Kruh: polomer = " + polomer + ", plocha = " + spoctiplochu() + ">"; public class SpoctiRozdilPlochObj { public static void main(string[] args) { Kruh kruh = new Kruh(10.0); Kruh krouzek = new Kruh(); System.out.println(kruh); System.out.println(krouzek); System.out.println("Rozdil ploch: " + kruh.spoctirozdilploch(krouzek)); <Kruh: polomer = 10.0, plocha = 314.1592653589793> <Kruh: polomer = 1.0, plocha = 3.141592653589793> Rozdil ploch: 311.01767270538954 Strana 36 (celkem 37)
Další jednoduché úložky: 1. Vytvořte program, který bude fungovat jako kodér a dekodér pro znaky Morseovy abecedy. 2. Celé číslo nazveme super číslem, jestliže ho můžeme vyjádřit jako součet dvou čtverců nebo jako podíl dvou čtverců. Napište program, který ověří, zda číslo je či není super číslem, víte-li, že např. rok 1914 nebyl super rokem! Strana 37 (celkem 37)