Přednášky KIV/PPA1, A. Netrvalová, 2016 6. přednáška
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.
Strana 2 (celkem 37)
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 3 (celkem 37)
Příklad: třída Kruh
Kruh o poloměru r s výpočtem plochy P
Příklad objektů třídy Kruh
P = 3.14
r = 1
1
P = r2
r
Kruh
double polomer
double spoctiPlochu()
mujKruhZluty
polomer = 1.0 P = 3.14
mujKruhModry
polomer = 2.0 P = 12.56
P = 12.56
r = 2
Objekt (object), instance (instance)
- datový prvek (množina hodnot a množina operací), vytvořený dle vzoru třídy
Strana 4 (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 ...
} }
Deklarace a vytvoření objektu
Přístup k objektům
- prostřednictvím referenční proměnné
např. mujKruhZluty, mujKruhModry
class Kruh {
double polomer = 1.0;
double spoctiPlochu() { return 3.14*polomer*polomer; } }
Strana 5 (celkem 37)
Deklarace objektu
JmenoTridy jmenoObjektu;
Příklad:
Vytvoření objektu
jmenoObjektu = new JmenoTridy();
Příklad:
Kruh mujKruh;
mujKruh = new Kruh();
null
mujKruh
referenční proměnná
mujKruh
polomer = 1
Kruh
objekt referenční
proměnná
Strana 6 (celkem 37)
Deklarace a vytvoření objektu současně
JmenoTridy jmenoObjektu = new JmenoTridy();
Příklad:
Zrušení objektu (Garbage collector) - pokud na objekt není reference Příklad:
Kruh mujKruh = new Kruh();
mujKruh = null;
mujKruh
null
referenční
proměnná
polomer = 1
Kruh
objekt
Strana 7 (celkem 37)
Proměnné primitivní vs. objektové
Rozdíl v pojetí
- při deklaraci a vzniku
- při přiřazení proměnných
int i = 1; Kruh k1 = new Kruh(5); int j = 2; Kruh k2 = new Kruh(9);
???
Kruh
polomer = 1
Primitivní typ int i; i
i = 1; i
Objektový typ Kruh k = new Kruh();
null
k
k při deklaraci
při vytvoření
1
při deklaraci
při vytvoření
1
Kruh
polomer = 5
Přiřazení: primitivní typ i = j
před:
i
2 j
2
po:
i
2 j
Přiřazení: typ objekt k1 = k2
před:
k1
k2
po:
k1
k2
polomer = 9
Kruh
Strana 8 (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ř.:
Reference metody
jmenoObjektu.metoda()
Př.:
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.
mujKruh.spoctiPlochu()
mujKruh.polomer
Strana 9 (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 10 (celkem 37)
Příklad vytvoření a použití objektu
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.
class Kruh {
double polomer = 1.0;
double spoctiPlochu(){ return 3.14*polomer*polomer; } }
TŘÍDA KRUH
public class TestKruhu { 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.
HLAVNÍ PROGRAM TŘÍDA - obsahující main() (ŘÍDICÍ, APLIKAČNÍ, UŽIVATELSKÁ)
Strana 11 (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).
public class TestKruhu {
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); } }
class Kruh {
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() + ">"; } }
Strana 12 (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 13 (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 14 (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:
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).
Specifikátor Povolený přístup
public Z libovolné třídy.
private Pouze zevnitř dané třídy, žádný přístup z vnějšku.
protected Z kterékoliv třídy téhož balíku, případně z potomka třídy kdekoliv.
žádný (tzv. package friendly)
Z kterékoliv třídy téhož balíku.
Strana 15 (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){ //osetri pripustnost vstupu this.polomer = polomer; } }
double spoctiPlochu(){ return polomer*polomer*Math.PI; }
public String toString(){ return "<Kruh: polomer = " + polomer + ", plocha = " + spoctiPlochu() + ">"; } }
Strana 16 (celkem 37)
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
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>
Strana 17 (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
1 2 3 4$
0
Rex
Lady Lord
null null
1 2 3 0
smeckadatum
objekt Pes
objekt Pes
objekt Pes
4
stene
pole referencí na objekty Pes 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 18 (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 19 (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 20 (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) { // konstruktor
text = pozdrav; } // privatni metoda - privatni getr
private String getText() { // zde private ok
return text; } // 1 - metoda pro vypis
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(); } }
Ahoj světe! Ahoj světe! Hello world! Hello world!
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 21 (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.
BMI = m / (v * v)
Hodnoty BMI:
< 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 22 (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 23 (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
- ř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)
Např.:
String s = "Ahoj"; char c = s.charAt(0); // A = znak na pozici 0
// 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);
…
s1: retezec s2: retezec s3: retezec
Strana 24 (celkem 37)
Práce se znaky
Porovnávání řetězců
Příklad: totožnost - výsledek true/false
Příklad: hodnotou - výsledek (0: rovnost, <0: první je menší, >0: druhé je menší)
Práce s podřetězci
Test začátku a konce řetězce
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'
String s1 = "Ahoj";
String s2 = "ahoj"; boolean shoda = s1.equals(s2); // false
String s1 = "Ahoj";
String s2 = "ahoj";
int k = s1.compareTo(s2); // <0
String s = "proto"; int i = s.indexOf("to"); // výsledek i= 3
String p = s.substring(2); // výsledek p="oto"
String s = "proto"; boolean z = s.startsWith("pr"); // výsledek z = true
boolean k = s.endsWith(''ale"); // výsledek z = false
Strana 25 (celkem 37)
Náhrada všech určených znaků
Oříznutí bílých znaků
Spojení řetězců (konkatenace)
Převod řetězce na pole znaků a zpět
KONVERZE:
A. Řetězec → základní datové typy
Datové typy int, double, long, ... mají své obalovací třídy: Integer, Double, Long, ...
String s = "\t ahoj \t\n\r";
s = s.trim(); // ahoj
String s2,s1 = "cacao";
s2 = s1.replace('c', 'k'); // vysledek kakao
String s1 = "Pan"; String s2 = "TAU"; // operatorem +
String s3 = s1 + " " + s2; // metodou concat()
String s4 = s1.concat(" " + s2); // Pan TAU
String s1 = "retezec"; char poleznaku[] = s1.toCharArray(); // pouziti pretizeneho konstruktoru
String s2 = new String(poleznaku);
Strana 26 (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)
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),
// 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
Strana 27 (celkem 37)
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(" "); // oddelovac 1 mezera a = Integer.parseInt(idata[0]); b = Integer.parseInt(idata[1]); }
// 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"
Strana 28 (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 29 (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".
Další podobnou úložku hledejte na konci přednášky…
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
Strana 30 (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 31 (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 32 (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.
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
// 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);
StringBuffer buf = new StringBuffer("jmeno :"); buf.append(" Koza"); buf.insert(8, " Oliver") // vystup: "jmeno : Oliver Koza"; System.out.println(buf.toString());
Strana 33 (celkem 37)
replace() - změna textu ve StringBufferu
capacity() - zjištění kapacity StringBufferu.
Kapacita představuje maximalní počet znaků, který lze do StringBufferu uložit.
reverse() - obrácení textu ve StringBufferu
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?
StringBuffer buf = new StringBuffer("Miroslav Koula"); String s1 = "Mirek"; // nahradi text zacinajici na pozici 1 až 8 novym textem buf.replace(1,8,s1);
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();
StringBuffer obraceni = new StringBuffer("Radar"); System.out.println("Obraceni Radar: " + obraceni.reverse());
Strana 34 (celkem 37)
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ů.
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)));
Strana 35 (celkem 37)
Procedurálně: Počítáme rozdíl dvou ploch.
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ě.
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
Strana 36 (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 37 (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!