├── java-cvika.html ├── java-cvika.md ├── java.html └── java.md /java-cvika.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | java-cvika 578 | 579 | 580 |

Java (úkoly ze cvičení)

Násedují úkoly ze cvičení (2019/2020), kde to bylo možné tak se správnou odpovědí a vysvětlením. Důležité příklady, které bývají na zkouškách, jsou označeny jako zkouškový příklad.

Cvičení 1

Co se vypíše?

Řešení: NE

== porovnává pro referenční typy (což jsou všechny objekty, i Integer) pouze ukazatele do paměti, ne hodnoty. i1 a i2 jsou v tomto případě různé objekty s různými pozicemi v paměti.

Co se vypíše?

Řešení: 2147483647 -2147483648

2147483647 je Integer.MAX_VALUE, když k ní přičteme jedničku, dojde k overflow (jede se opět "od začátku" intu).

Co se vypíše?

Řešení: url: :url

V http://google.com/ se vše po // bere jako komentář a http: se bere jako label. Labely fungují podobně jako v Pascalu, lze na ně skočit pomocí continue.

Co se vypíše?

Řešení: 0 10

a ^= b odpovídá a = a ^ b. a ^ b je operace bitwise XOR, při níž se a a b berou jako bity (čili pokud to jsou integery, berou se převedené do binární soustavy). Kratší z nich se zepředu doplní nulami, aby byla obě čísla stejně dlouhá. Poté se porovná i-tý bit z a s i-tým bitem z b pomocí operace XOR.

x ^= y ^= x ^= y lze pak přepsat jako x = x ^ (y = y ^ (x = x ^ y)), což je výraz, který se vyhodnocuje zleva. Po dosazení vyjde x = 10 ^ (y = 20 ^ (x = 10 ^ y)) atd.

Co se vypíše?

Řešení: Nekonečný cyklus (nevypíše se nic)

int i nikdy nebude větší než Integer.MAX_VALUE, protože je to jeho horní hranice.

Cvičení 2

Doplňte deklaraci i, aby se vypsalo ANO

Řešení: i = Integer.MIN_VALUE

Když ho znegujeme, dostaneme Integer.MAX_VALUE + 1, což je zase Integer.MIN_VALUE.

Co se vypíše?

Řešení: 0

Má to co dočinění s floating-point čísly. START je sice na začátku int, kvůli porovnání s f je však převeden na float. START jen o málo menší než , proto v jeho binárním zápisu bude určitě 31. bit jednička. float čísla jsou sice 32 bitová, ale 1 bit z toho je na znaménko, dalších 8 je na exponent a tak na samotné číslo zbude pouze 23 bitů.

Protože k uložení start potřebujeme mít 31. bit nastavený na 1, při převodu na float si ze START necháme následujících 23 bitů: [31., 30., 29., ..., 8.] — jinými slovy prvních sedm bitů ze START odstřihneme, neboť se nám do floatu nevlezou. Protože přičtená 50 se vleze do prvních sedmi bitů, a my těchto sedm bitů poté odstřihneme, přičtení 50 se vůbec neprojeví a platí START == f == START + 50 (pokud je START převeden na float).

Cvičení 3

Co se vypíše?

Řešení: false

finally přebíjí většinu věcí, i return.

Co se vypíše?

Řešení: "Hello world!"

finally přebíjí většinu věcí, ale System.exit() je jedna z výjimek — prostě rovnou ukončí průběh programu. Kromě něj takto funguje i halt a pak už většinou jen pády JVM nebo samotného operačního systému.

Co se vypíše?

Řešení: ParamsTest(long[] a)

Podle skutečných parametrů se vybere ta nejspecifičtější vyhovující implementace (zde long[] a).

Co se vypíše? (zkouškový příklad)

Řešení: 2 1 1

Statické metody se koukají pouze na typ objektu, ne na jeho hodnotu; podle toho se pak zavolá konkrétní implementace. Viz také tato otázka na Stack Overflow.

Cvičení 4

Co program udělá? (zkouškový příklad)

Řešení: vypíše se "Hello world!"

Že se třída jmenuje Null je v pořádku. Poté sice voláme null.hello(), ale hello() je statická metoda, čili vůbec nekouká na reálnou hodnotu objektu — pouze na jeho typ (a to je Null). Vše tedy funguje, jak má.

Co program udělá?

Řešení: Myslím, že vyhodí StackOverflowError.

Co program vypíše?

Řešení: Nepřeloží se, ve třídě Test02 je chyba.

Deklarace className v B schová atribut className z A (doslova se to jmenuje field hiding). To, že je sama private na věci nic nemění. Protože původní className z A je schovaná a className z B je zase private, je chyba vůbec se snažit tohoto atributu dosáhnout.

Cvičení 5

Co se vypíše?

Řešení: Je to úplně v pořádku, vypíše se Hello.

V interfacu mohou totiž být i statické metody.

Co se vypíše? (zkouškový příklad)

Řešení: Je to úplně v pořádku, vypíše se Hello.

enum je v podstatě jen vylepšená třída, proto může obsahovat statické metody. Nemůže však dědit, neboť implicitně již dědí od java.lang.Enum. Může dokonce obsahovat i abstraktní metody, pak je ale musí implementovat každý z prvků enumu.

Cvičení 6

Co se vypíše?

Řešení: Nevypíše se nic.

PrintStream.write() sice na stream přidá dané znaky, ale stream pak automaticky nevyprázdní do konzole — proto nejde nic vidět. Naproti tomu println() se o toto stará, čili kdybychom za loop přidali System.out.println("");, vypsalo by se už Hello world.

Co se vypíše?

Řešení: Trida cz.cuni.mff.java.io.Slasher musi byt v souboru ///////////////////////////.java

String.replaceAll() bere jako první argument regex, ne obyčejný string. Proto . je interpretováno regex enginem jako "jakýkoli znak" a všechny znaky jsou proto nahrazeny lomítkem.

Cvičení 7

Co program udělá?

Řešení: Přeloží se, ale při runtimu vyhodí chybu, že mu chybí metoda main.

main má totiž v této chvíli mít hlavičku public static void main(java.lang.String[] args), protože String je teď ta naše nová třída a ne původní String.

Lze třídu B nadeklarovat tak, aby program vypsal false? (bez přepsání equals)

Řešení: Ano, ale je to dost podvod.

Cvičení 8

Co se vypíše?

Řešení: Ping Pong

Obě metody jsou static synchronized, čili berou zámek přímo od třídy Test01. Když už jsme v main, má současné vlákno zámek (protože vstoupilo do synchronized bloku) a tak se vlákno t (potažmo metoda pong()) spustí až poté, co skončí to naše vlákno.

Co se vypíše?

Řešení: Interrupted: false

Thread.interrupted() totiž nejen vrátí současnou hodnotu .interrupted(), ale také ji resetuje na false. Kdyby se místo toho použilo this.isInterrupted(), který po vrácení žádný reset neprovádí, vypsalo by se Interrupted: true.

Cvičení 9

Co se vypíše?

Řešení: ain

V case nejsou breaky, takže word je vždy nakonec nastaven na new StringBuffer('M'). Protože StringBuffer dostal char (potažmo int) bere to jako hranici kapacity (ne jako první písmeno — to by musel dostat "M").

Co se vypíše?

Řešení: Ha 169

char + char je v tomto případě interpretováno jako součet intů. Pro zajímavost, println("" + 'H' + 'a') by vypsalo skutečně Ha [laughs in javascript].

Cvičení 10

Lze definovat i tak, aby byl cyklus nekonečný?

Řešení: Ano, Double.NaN se nerovná ničemu, ani sám sobě.

Co se vypíše?

Řešení: 0

(Myslím, že) j++ vrátí 0 a nastaví j na 1; j = j++ pak vezme 0 z j++ a uloží jí do j.

Cvičení 11

Lze od této třídy (bez použití reflection API) vytvořit další instance (kromě instance v atributu INSTANCE)?

Řešení: Leda bychom přidali něco do třídy samotné (jinak máme příklad tzv. singleton pattern, což je třída pouze s jednou instancí, zde konkrétně INSTANCE).

V tomto případě naopak používám tzv. factory pattern (máme metody, které nejsou konstruktory, ale přesto vyrábějí a vrací objekt své třídy).

Cvičení 12

Lze napsat deklaraci proměnné i tak, aby následující cyklus byl nekonečný?

Řešení: Ano, např. String i = "a", potom i + 0 == "a0".

Lze napsat deklaraci proměnných i a j tak, aby následující cyklus byl nekonečný?

Řešení: Ano, například i = new Integer(1) a j = new Integer(1).

Protože se jedná o referenční typy (objekty), výraz i != j je pravda, protože porovnává umístění v paměti a ne samotné hodnoty i a j.

 

581 | 582 | -------------------------------------------------------------------------------- /java-cvika.md: -------------------------------------------------------------------------------- 1 | # Java (úkoly ze cvičení) 2 | 3 | Násedují úkoly ze cvičení (2019/2020), kde to bylo možné tak se správnou odpovědí a vysvětlením. Důležité příklady, které bývají na zkouškách, jsou označeny jako *zkouškový příklad*. 4 | 5 | ## Cvičení 1 6 | 7 | **Co se vypíše?** 8 | 9 | ```java 10 | Integer i1 = new Integer(1); 11 | Integer i2 = new Integer(1); 12 | if (i1 == i2) 13 | System.out.println("ANO"); 14 | else 15 | System.out.println("NE"); 16 | ``` 17 | 18 | *Řešení:* NE 19 | 20 | `==` porovnává pro referenční typy (což jsou všechny objekty, i `Integer`) pouze ukazatele do paměti, ne hodnoty. `i1` a `i2` jsou v tomto případě různé objekty s různými pozicemi v paměti. 21 | 22 | **Co se vypíše?** 23 | 24 | ```java 25 | public class Overflow { 26 | public static void main(String[] argv) { 27 | int b = 2147483647; 28 | System.out.println(b); 29 | b = b + 1; 30 | System.out.println(b); 31 | } 32 | } 33 | ``` 34 | 35 | *Řešení:* 2147483647 -2147483648 36 | 37 | 2147483647 je Integer.MAX_VALUE, když k ní přičteme jedničku, dojde k *overflow* (jede se opět "od začátku" intu). 38 | 39 | **Co se vypíše?** 40 | 41 | ```java 42 | class URL { 43 | public static void main(String[] argv) { 44 | System.out.println("url:"); 45 | http://google.com/ 46 | System.out.println(":url"); 47 | } 48 | } 49 | ``` 50 | 51 | *Řešení:* url: :url 52 | 53 | V `http://google.com/` se vše po `//` bere jako komentář a `http:` se bere jako label. Labely fungují podobně jako v Pascalu, lze na ně skočit pomocí `continue`. 54 | 55 | **Co se vypíše?** 56 | 57 | ```java 58 | public class Swap { 59 | public static void main(String[] argv) { 60 | int x = 10; 61 | int y = 20; 62 | x ^= y ^= x ^= y; 63 | System.out.println(x); 64 | System.out.println(y); 65 | } 66 | } 67 | ``` 68 | 69 | *Řešení:* 0 10 70 | 71 | `a ^= b` odpovídá `a = a ^ b`. `a ^ b` je operace bitwise `XOR`, při níž se `a` a `b` berou jako bity (čili pokud to jsou integery, berou se převedené do binární soustavy). Kratší z nich se zepředu doplní nulami, aby byla obě čísla stejně dlouhá. Poté se porovná i-tý bit z `a` s i-tým bitem z `b` pomocí operace XOR. 72 | 73 | `x ^= y ^= x ^= y` lze pak přepsat jako `x = x ^ (y = y ^ (x = x ^ y))`, což je výraz, který se vyhodnocuje zleva. Po dosazení vyjde `x = 10 ^ (y = 20 ^ (x = 10 ^ y))` atd. 74 | 75 | **Co se vypíše?** 76 | 77 | ```java 78 | class ForCycle { 79 | public static void main(String[] argv) { 80 | int j = 0; 81 | for (int i = Integer.MAX_VALUE - 10; i <= Integer.MAX_VALUE; i++) { 82 | j++; 83 | } 84 | System.out.println(j); 85 | } 86 | } 87 | ``` 88 | 89 | *Řešení:* Nekonečný cyklus (nevypíše se nic) 90 | 91 | `int i` nikdy nebude větší než `Integer.MAX_VALUE`, protože je to jeho horní hranice. 92 | 93 | ## Cvičení 2 94 | 95 | **Doplňte deklaraci `i`, aby se vypsalo `ANO`** 96 | 97 | ```java 98 | if (i == -i && i != 0) { 99 | System.out.println(“ANO“); 100 | } else { 101 | System.out.println(“NE“); 102 | } 103 | ``` 104 | 105 | *Řešení:* `i = Integer.MIN_VALUE` 106 | 107 | Když ho znegujeme, dostaneme `Integer.MAX_VALUE + 1`, což je zase `Integer.MIN_VALUE`. 108 | 109 | **Co se vypíše?** 110 | 111 | ```java 112 | public class LoopTest { 113 | public static void main(String[] argv) { 114 | int START = 2000000000; 115 | int count = 0; 116 | for (float f = START; f < START + 50; f++) { 117 | count++; 118 | } 119 | System.out.println(count); 120 | } 121 | } 122 | ``` 123 | 124 | *Řešení:* 0 125 | 126 | Má to co dočinění s *floating-point* čísly. `START` je sice na začátku `int`, kvůli porovnání s `f` je však převeden na `float`. `START` jen o málo menší než $2^{31}$, proto v jeho binárním zápisu bude určitě 31. bit jednička. `float` čísla jsou sice 32 bitová, ale 1 bit z toho je na znaménko, dalších 8 je na exponent a tak na samotné číslo zbude pouze 23 bitů. 127 | 128 | Protože k uložení start potřebujeme mít 31. bit nastavený na 1, při převodu na `float` si ze `START` necháme následujících 23 bitů: [31., 30., 29., ..., 8.] — jinými slovy prvních sedm bitů ze `START` odstřihneme, neboť se nám do floatu nevlezou. Protože přičtená 50 se vleze do prvních sedmi bitů, a my těchto sedm bitů poté odstřihneme, přičtení 50 se vůbec neprojeví a platí `START == f == START + 50` (pokud je `START` převeden na `float`). 129 | 130 | ## Cvičení 3 131 | 132 | **Co se vypíše?** 133 | 134 | ```java 135 | public class Test01 { 136 | public static void main(String[] argv) { 137 | System.out.println(test()); 138 | } 139 | public static boolean test() { 140 | try { 141 | return true; 142 | } finally { 143 | return false; 144 | } 145 | } 146 | } 147 | ``` 148 | 149 | *Řešení:* `false` 150 | 151 | `finally` přebíjí většinu věcí, i `return`. 152 | 153 | **Co se vypíše?** 154 | 155 | ```java 156 | public class Test01 { 157 | public static void main(String[] argv) { 158 | try { 159 | System.out.println("Hello world!"); 160 | System.exit(0); 161 | } finally { 162 | System.out.println("Goodbye"); 163 | } 164 | } 165 | } 166 | ``` 167 | 168 | *Řešení:* "Hello world!" 169 | 170 | `finally` přebíjí většinu věcí, ale `System.exit()` je jedna z výjimek — prostě rovnou ukončí průběh programu. Kromě něj takto funguje i `halt` a pak už většinou jen pády JVM nebo samotného operačního systému. 171 | 172 | **Co se vypíše?** 173 | 174 | ```java 175 | class ParamsTest { 176 | public ParamsTest(Object o) { 177 | System.out.println("ParamsTest(Object o)"); 178 | } 179 | public ParamsTest(long[] a) { 180 | System.out.println("ParamsTest(long[] a)"); 181 | } 182 | public static void main(String[] argv) { 183 | new ParamsTest(null); 184 | } 185 | } 186 | ``` 187 | 188 | *Řešení:* ParamsTest(long[] a) 189 | 190 | Podle skutečných parametrů se vybere ta nejspecifičtější vyhovující implementace (zde `long[] a`). 191 | 192 | **Co se vypíše?** (zkouškový příklad) 193 | 194 | ```java 195 | class A { 196 | int x = 1; 197 | } 198 | 199 | class B extends A { 200 | int x = 2; 201 | public void foo() { 202 | System.out.println(this.x); 203 | System.out.println(super.x); 204 | System.out.println(((A)this).x); 205 | } 206 | public static void main(String[] args) { 207 | B b = new B(); 208 | b.foo(); 209 | } 210 | } 211 | ``` 212 | 213 | *Řešení:* 2 1 1 214 | 215 | Statické metody se koukají pouze na typ objektu, ne na jeho hodnotu; podle toho se pak zavolá konkrétní implementace. Viz také [tato otázka na Stack Overflow](https://stackoverflow.com/questions/60065506/inherited-attribute-method-static-method-behavior?noredirect=1). 216 | 217 | ## Cvičení **4** 218 | 219 | **Co program udělá?** (zkouškový příklad) 220 | 221 | ```java 222 | public class Null { 223 | public static void main(String[] argv) { 224 | ((Null) null).hello(); 225 | } 226 | public static void hello() { 227 | System.out.println("Hello world!"); 228 | } 229 | } 230 | ``` 231 | 232 | *Řešení:* vypíše se "Hello world!" 233 | 234 | Že se třída jmenuje `Null` je v pořádku. Poté sice voláme `null.hello()`, ale `hello()` je statická metoda, čili vůbec nekouká na reálnou hodnotu objektu — pouze na jeho typ (a to je `Null`). Vše tedy funguje, jak má. 235 | 236 | **Co program udělá?** 237 | 238 | ```java 239 | class Test01 { 240 | public static void main(String[] argv) { 241 | run(); 242 | System.out.println("Konec"); 243 | } 244 | 245 | public static void run() { 246 | try { 247 | run(); 248 | } finally { 249 | run(); 250 | } 251 | } 252 | } 253 | ``` 254 | 255 | *Řešení:* Myslím, že vyhodí `StackOverflowError`. 256 | 257 | **Co program vypíše?** 258 | 259 | ```java 260 | class A { 261 | public String className = "A"; 262 | } 263 | 264 | class B extends A { 265 | private String className = "B"; 266 | } 267 | 268 | public class Test02 { 269 | public static void main(String[] argv) { 270 | System.out.println(new B().className); 271 | } 272 | } 273 | ``` 274 | 275 | *Řešení:* Nepřeloží se, ve třídě Test02 je chyba. 276 | 277 | Deklarace `className` v `B` schová atribut `className` z `A ` (doslova se to jmenuje *field hiding*). To, že je sama `private` na věci nic nemění. Protože původní `className` z `A` je schovaná a `className` z `B` je zase `private`, je chyba vůbec se snažit tohoto atributu dosáhnout. 278 | 279 | ## Cvičení 5 280 | 281 | **Co se vypíše?** 282 | 283 | ```java 284 | public interface Test { 285 | public static void main(String[] argv) { 286 | System.out.println("Hello"); 287 | } 288 | } 289 | ``` 290 | 291 | *Řešení:* Je to úplně v pořádku, vypíše se Hello. 292 | 293 | V interfacu mohou totiž být i statické metody. 294 | 295 | **Co se vypíše?** (zkouškový příklad) 296 | 297 | ```java 298 | public enum Test { 299 | RED, GREEN, BLUE; 300 | 301 | public static void main(String[] argv) { 302 | System.out.println("Hello"); 303 | } 304 | } 305 | ``` 306 | 307 | *Řešení:* Je to úplně v pořádku, vypíše se Hello. 308 | 309 | `enum` je v podstatě jen vylepšená třída, proto může obsahovat statické metody. Nemůže však dědit, neboť implicitně již dědí od `java.lang.Enum`. Může dokonce obsahovat i abstraktní metody, pak je ale musí implementovat každý z prvků enumu. 310 | 311 | ## Cvičení 6 312 | 313 | **Co se vypíše?** 314 | 315 | ```java 316 | public class Greeter { 317 | public static void main (String[] args) { 318 | String greeting = "Hello world"; 319 | for (int i = 0; i < greeting.length(); i++) { 320 | System.out.write(greeting.charAt(i)); 321 | } 322 | } 323 | } 324 | ``` 325 | 326 | *Řešení:* Nevypíše se nic. 327 | 328 | `PrintStream.write()` sice na stream přidá dané znaky, ale stream pak automaticky nevyprázdní do konzole — proto nejde nic vidět. Naproti tomu `println()` se o toto stará, čili kdybychom za loop přidali `System.out.println("");`, vypsalo by se už `Hello world`. 329 | 330 | **Co se vypíše?** 331 | 332 | ```java 333 | class Slasher { 334 | public static void main(String[] argv) { 335 | String fullClassName = "cz.cuni.mff.java.io.Slasher"; 336 | String fileName = fullClassName.replaceAll(".", "/") + ".java"; 337 | System.out.println("Trida " + fullClassName + " musi byt v souboru " + fileName); 338 | } 339 | } 340 | ``` 341 | 342 | *Řešení*: Trida cz.cuni.mff.java.io.Slasher musi byt v souboru ///////////////////////////.java 343 | 344 | `String.replaceAll()` bere jako první argument `regex`, ne obyčejný string. Proto `.` je interpretováno regex enginem jako "jakýkoli znak" a všechny znaky jsou proto nahrazeny lomítkem. 345 | 346 | ## Cvičení 7 347 | 348 | **Co program udělá?** 349 | 350 | ```java 351 | public class TestString { 352 | public static void main(String[] args) { 353 | String s = new String("Hello world"); 354 | System.out.println(s); 355 | } 356 | } 357 | 358 | class String { 359 | private final java.lang.String s; 360 | public String(java.lang.String s) { 361 | this.s = s; 362 | } 363 | public java.lang.String toString() { 364 | return s; 365 | } 366 | } 367 | ``` 368 | 369 | *Řešení:* Přeloží se, ale při runtimu vyhodí chybu, že mu chybí metoda `main`. 370 | 371 | `main` má totiž v této chvíli mít hlavičku `public static void main(java.lang.String[] args)`, protože `String` je teď ta naše nová třída a ne původní `String`. 372 | 373 | **Lze třídu `B` nadeklarovat tak, aby program vypsal `false`? (bez přepsání `equals`)** 374 | 375 | ```java 376 | public class A { 377 | public static void main(String[] args) { 378 | B b = new B(); 379 | System.out.println(b.equals(b)); 380 | } 381 | } 382 | ``` 383 | 384 | *Řešení:* Ano, ale je to dost podvod. 385 | 386 | ```java 387 | class B { 388 | public B() { 389 | System.out.println(false); 390 | System.exit(0); 391 | } 392 | } 393 | ``` 394 | 395 | ## Cvičení 8 396 | 397 | **Co se vypíše?** 398 | 399 | ```java 400 | public class Test01 { 401 | public static synchronized void main(String[] a) { 402 | Thread t = new Thread() { 403 | public void run() { 404 | pong(); 405 | } 406 | }; 407 | t.start(); 408 | System.out.println("Ping"); 409 | } 410 | 411 | static synchronized void pong() { 412 | System.out.println("Pong"); 413 | } 414 | } 415 | ``` 416 | 417 | *Řešení:* Ping Pong 418 | 419 | Obě metody jsou `static synchronized`, čili berou zámek přímo od třídy `Test01`. Když už jsme v `main`, má současné vlákno zámek (protože vstoupilo do `synchronized` bloku) a tak se vlákno `t` (potažmo metoda `pong()`) spustí až poté, co skončí to naše vlákno. 420 | 421 | **Co se vypíše?** 422 | 423 | ```java 424 | class SelfInterruption { 425 | public static void main(String[] args) { 426 | Thread.currentThread().interrupt(); 427 | if (Thread.interrupted()) { 428 | System.out.println("Interrupted: " + Thread.interrupted()); 429 | } else { 430 | System.out.println("Not interrupted: " + Thread.interrupted()); 431 | } 432 | } 433 | } 434 | ``` 435 | 436 | *Řešení:* Interrupted: false 437 | 438 | `Thread.interrupted()` totiž nejen vrátí současnou hodnotu `.interrupted()`, ale také ji resetuje na `false`. Kdyby se místo toho použilo `this.isInterrupted()`, který po vrácení žádný reset neprovádí, vypsalo by se *Interrupted: true*. 439 | 440 | ## Cvičení 9 441 | 442 | **Co se vypíše?** 443 | 444 | ```java 445 | public class Test01 { 446 | private static java.util.Random rnd = new java.util.Random(); 447 | 448 | public static void main(String[] args) { 449 | StringBuffer word = null; 450 | switch (rnd.nextInt(2)) { 451 | case 1: 452 | word = new StringBuffer('P'); 453 | case 2: 454 | word = new StringBuffer('G'); 455 | default: 456 | word = new StringBuffer('M'); 457 | } 458 | word.append('a'); 459 | word.append('i'); 460 | word.append('n'); 461 | System.out.println(word); 462 | } 463 | } 464 | ``` 465 | 466 | *Řešení:* ain 467 | 468 | V `case` nejsou breaky, takže word je vždy nakonec nastaven na `new StringBuffer('M')`. Protože `StringBuffer` dostal `char` (potažmo `int`) bere to jako hranici kapacity (ne jako první písmeno — to by musel dostat `"M"`). 469 | 470 | **Co se vypíše?** 471 | 472 | ```java 473 | public class Test02 { 474 | public static void main(String args[]) { 475 | System.out.println("H" + "a"); 476 | System.out.println('H' + 'a'); 477 | } 478 | } 479 | ``` 480 | 481 | *Řešení:* Ha 169 482 | 483 | `char` + `char` je v tomto případě interpretováno jako součet intů. Pro zajímavost, `println("" + 'H' + 'a')` by vypsalo skutečně `Ha` [[*laughs in javascript*](https://www.destroyallsoftware.com/talks/wat)]. 484 | 485 | ## Cvičení 10 486 | 487 | **Lze definovat `i` tak, aby byl cyklus nekonečný?** 488 | 489 | ```java 490 | while (i != i) { } 491 | ``` 492 | 493 | *Řešení:* Ano, `Double.NaN` se nerovná ničemu, ani sám sobě. 494 | 495 | **Co se vypíše?** 496 | 497 | ```java 498 | public class Increment { 499 | public static void main(String[] args) { 500 | int j = 0; 501 | for (int i = 0; i < 100; i++) { 502 | j = j++; 503 | } 504 | System.out.println(j); 505 | } 506 | } 507 | ``` 508 | 509 | *Řešení:* 0 510 | 511 | (Myslím, že) `j++` vrátí 0 a nastaví `j` na 1; `j = j++` pak vezme 0 z `j++` a uloží jí do `j`. 512 | 513 | ## Cvičení 11 514 | 515 | **Lze od této třídy (bez použití reflection API) vytvořit další instance (kromě instance v atributu `INSTANCE`)?** 516 | 517 | ```java 518 | public class Dog implements Serializable { 519 | public static final Dog INSTANCE = new Dog(); 520 | private Dog() { } 521 | public String toString() { 522 | return "Woof"; 523 | } 524 | } 525 | ``` 526 | 527 | *Řešení:* Leda bychom přidali něco do třídy samotné (jinak máme příklad tzv. **singleton pattern**, což je třída pouze s jednou instancí, zde konkrétně `INSTANCE`). 528 | 529 | ```java 530 | public class Dog implements Serializable { 531 | public static final Dog INSTANCE = new Dog(); 532 | private Dog() { } 533 | public String toString() { 534 | return "Woof"; 535 | } 536 | 537 | public Dog getDog() { 538 | return new Dog(); 539 | } 540 | } 541 | 542 | Dog d = Dog.getDog(); 543 | ``` 544 | 545 | V tomto případě naopak používám tzv. **factory pattern** (máme metody, které nejsou konstruktory, ale přesto *vyrábějí* a vrací objekt své třídy). 546 | 547 | ## Cvičení 12 548 | 549 | **Lze napsat deklaraci proměnné `i` tak, aby následující cyklus byl nekonečný?** 550 | 551 | ```java 552 | while (i != i + 0) { } 553 | ``` 554 | 555 | *Řešení:* Ano, např. `String i = "a"`, potom `i + 0 == "a0"`. 556 | 557 | **Lze napsat deklaraci proměnných `i` a `j` tak, aby následující cyklus byl nekonečný?** 558 | 559 | ```java 560 | while (i <= j && j <= i && i != j) { } 561 | ``` 562 | 563 | *Řešení:* Ano, například `i = new Integer(1)` a `j = new Integer(1)`. 564 | 565 | Protože se jedná o referenční typy (objekty), výraz `i != j` je pravda, protože porovnává umístění v paměti a ne samotné hodnoty `i` a `j`. 566 | 567 | -------------------------------------------------------------------------------- /java.md: -------------------------------------------------------------------------------- 1 | # Java (zkouška) 2 | 3 | Následuje seznam důležitých věcí, které je třeba vědět, a pod tím zkouškové příklady. 4 | 5 | ## Co je potřeba vědět 6 | 7 | Seznam věcí, na které se na zkoušce často (i nepřímo) ptá. 8 | 9 | ### Keywordy 10 | 11 | běžné **keywordy** jsou následující: `abstract`, `assert`, `boolean`, `break`, `byte`, `case`, `catch`, `char`, `class`, `continue`, `default`, `double`, `else`, `enum`, `extends`, `finally`, `float`, `for`, `if`, `implements`, `import`, `int`, `interface`, `long`, `new`, `package`, `private`, `protected`, `public`, `return`, `short`, `static`, `switch`, `this`, `throw`, `throws`, `try`, `void`, `while` 12 | 13 | zatímco ty nečekané jsou: 14 | 15 | - **const** a **goto**: zatím nedělají nic, jsou pouze rezervované 16 | - **do**: do/while loop 17 | - **final**: viz níže 18 | - **instanceof**: check třídy 19 | - **native**: metoda je implementovaná v Java Native Interface, kde Java spolupracuje s C++, C, Assemblerem apod. 20 | - **strictfp**: třída/interface/metoda, zaručí, že floating-point aritmentika vyjde na všech platformách stejně 21 | - **super**: k použití proměnných/metod z rodičovské třídy 22 | - **synchronized**: viz níže v multithreadingu 23 | - **transient**: při ukládání objektů pomocí Seriazable interface se takto označená proměnná neuloží 24 | - **volatile**: viz níže v multithreadingu 25 | 26 | ### Access modifiers 27 | 28 | - `private`: přístupné pouze z dané třídy 29 | - třídy a interfacy nemohou být `private` (pokud to nejsou vnitřní třídy) 30 | - žádný: přístupné všem třídám v současném balíku 31 | - `protected`: přístupné všem podtřídám dané třídy (i v jiném balíku) a všem třídám v současném balíku 32 | - třídy, interfacy a pole a metody v interfacu nemohou být `protected` 33 | - `public`: přístupné všemu, i z jiného balíku 34 | 35 | ### Final 36 | 37 | - `final` proměnná je konstantní (pokud se jedná o referenční proměnnou, její samotný stav se měnit může, pouze reference na ni ne) 38 | - `final` metoda se nedá overloadovat 39 | - `final` třída nejde subclassovat 40 | 41 | Používá se i při tvoření anonymních vnitřních tříd v metodách, objekty, které ve vnitřní třídě použijeme, musí být `final`, nebo alespoň efektivně `final` (tj. nemají explicitně `final`, ale nemění se). 42 | 43 | ```java 44 | public interface MyIface { 45 | int value(); 46 | } 47 | 48 | public class MyClass { 49 | public MyIface add(final int val) { 50 | return new MyIface() { 51 | private int i = val; 52 | public int value() { return i; } 53 | }; 54 | } 55 | } 56 | ``` 57 | 58 | ### Refereční a hodnotové typy 59 | 60 | - referenční: jsou někde v paměti a máme na ně pouze pointer 61 | - v Javě se píší s velkým písmenem 62 | - jedná se o všechny třídy a objekty (`String`, `ArrayList` atd.) 63 | - je možné do nich nastavit `null` jako nulový pointer 64 | - když je posíláme nějaké objekty jako argumenty do nějaké metody, posíláme tedy jen *pointer* na tyto objekty, a pokud metoda nějakým způsobem bude své argumenty měnit, projeví se to i u nás 65 | 66 | - hodnotové: jsou malé, pracujeme přímo s jejich hodnotou 67 | - v Javě se píší s malým písmenem 68 | - např. `boolean`, `int`, `byte`, `float` atd. 69 | - když je posíláme jako argumenty, pošleme pouze jejich hodnotu (zkopírují se), takže i pokud je metoda bude měnit, ty naše zůstanou nezměněny 70 | 71 | Porovnání `a == b` porovnává hodnoty uložené v `a` a `b`. U referečních typů jsou v `a` a `b` uložen pouze pointery na nějaké objekty, ne ty objekty samotné, proto například neplatí 72 | 73 | ```java 74 | String a = new String("a"); 75 | String b = new String("a"); 76 | a == b // false 77 | ``` 78 | 79 | `a` a `b` jsou v tomto případě pointery na dvě různá místa v paměti, tedy se nerovnají. To, jestli jsou na těchto *dvou různých místech* uloženy stringy se stejnou hodnotou zjistíme až pomocí `a.equals(b)`. 80 | Pozor ale na následující případ 81 | 82 | ```java 83 | String a = "a"; 84 | String b = "a"; 85 | a == b // true 86 | ``` 87 | 88 | Tady Java compiler použije tzv. **string pool** a obě proměnné odkáže na stejný string v paměti. 89 | 90 | ### Literály 91 | 92 | - neboli způsoby zapsání dat *doslova* v rámci kódu (běžné příklady: `10`, `"string"`, `3.3`, `false`) 93 | - `null` vyjadřuje prázdný pointer, proto jej lze nastavit **pouze u referenčních typů** 94 | - do `boolean` lze nastavit **pouze `false` a `true`** 95 | 96 | #### Chary 97 | 98 | - **jeden** znak v jednoduchých uvozovkách: `'c'` 99 | - číselný literál: `99` 100 | - případně i speciální znaky jako `'\n'` nebo unicodové znaky 101 | 102 | #### Čísla 103 | 104 | - `byte` má rozsah -128 až 127 105 | - integery lze zapisovat v různých soustavách: 106 | - osmičková: začínají na 0, např. `07` 107 | - pozor, `08` už je špatně, 8 v osmičkové neexistuje 108 | - binární: `0b01` 109 | - šesnáctková: `0xAB` 110 | - double lze psát i s exponenty: `1e10` 111 | - v rámci všech čísel jde pro přehlednost použít podtržítka: `1234_5678 ` 112 | 113 | ### Výjimky — teorie 114 | 115 | - všechny instance `Throwable` 116 | - z podtřídy `Error`: nikdy by se neměly odchytávat, signalizují velký problém 117 | - nebo z podtřídy `Exception`: někdy je možná chcete odchytit 118 | - `Exception` se dále dělí 119 | - *unchecked* (pouze podtřídy `RuntimeException`): kompilátoru nevadí, že je neřešíte 120 | - *checked* (všechny ostatní): musí být odchyceny nebo vyhozeny výše 121 | 122 | Ošetřují se pomocí try/catch/finally bloku. 123 | 124 | - v `try` lze použít i objekty, které jsou `AutoClosable`, poté lze vynechat `catch` i `finally` a objekty se samy zavřou 125 | - v `catch` lze odchytit více různých exception pomocí oddělení `|`, nebo lze za `try` dát více catchů 126 | - v druhém případě se to chová podobně jako if/else, jakmile se matchne jeden catch, další už se nezkoušejí 127 | - finally proběhne nehledě na to, jak dopadly věci v try/catch 128 | 129 | To, že metoda vyhazuje checked `Exception`, signalizujeme pomocí `throws`. 130 | 131 | - `Error` a `RuntimeException` nemusíme explicitně do `throws` dávat, je možné je vyhazovat vždy 132 | 133 | ```java 134 | class MyException extends java.lang.Exception {} 135 | 136 | public class A { 137 | public void foo(int i) throws MyException { 138 | if (i < 0) { 139 | throw new MyException(); 140 | } else if (i == 0) { 141 | throw new Error(); // V pořádku, i když není ve throws 142 | } else { 143 | throw new RuntimeException(); // V pořádku, i když není ve throws 144 | } 145 | } 146 | } 147 | ``` 148 | 149 | ### Multithreading — teorie 150 | 151 | - spouštění více *vláken* najednou 152 | - každé vlákno potřebuje vědět, co na něm poběží 153 | - v konstruktoru může dostat objekt, který implementuje `Runnable` interface (konkrétně metodu `run`) 154 | - samotná třída `Thread` je runnable, takže jí můžeme subclassovat a implementovat `run` sami (nedoporučuje se) 155 | - vlákno se po konstrukci musí spustit metodou `.start()` 156 | - vlákno jde přerušit pomocí `.interrupt()`, musí na to být ale připraveno (odchytnout `InterruptedException` nebo kontrolovat `Thread.interrupted`) 157 | - současné vlákno lze pozastavit do doby, než se dokončí vlákno `t` pomocí `t.join()` 158 | 159 | Kdyby dvě vlákna najednou upravovala jeden objekt, mohlo by dojít k chybám; proto má každý objekt *zámek*, který určuje, které vlákno s daným objektem zrovna pracuje. 160 | 161 | - vlákno si zámek daného objektu vezme, poté s objektem může pracovat a když je hotové, zámek uvolní 162 | 163 | - `synchronized (object) { ... }` zařídí, že kód v bloku bude spouštěn v jednu chvíli pouze jedním vláknem, kterému poskytne zámek objekt `object` (může jít o jakýkoli objekt, nemusí se poté v bloku vůbec vyskytnout) 164 | 165 | - vhodné pro stavy, kdy je hodně writerů i hodně readerů 166 | 167 | - `synchronized` může být i metoda 168 | 169 | ```java 170 | class C { 171 | synchronized void method() { 172 | /* ... */ 173 | } 174 | } 175 | ``` 176 | 177 | se chová jako 178 | 179 | ```java 180 | class C { 181 | void method() { 182 | synchronized (this) { 183 | /* ... */ 184 | } 185 | } 186 | } 187 | ``` 188 | 189 | Všechny `synchronized` ne-statické metody jednoho objektu se tedy blokují navzájem (mohou být najednou používany pouze jedním vláknem). Statické `synchronized` metody používají jako objekt k získání zámku samotnou třídu. 190 | 191 | Když ale nepotřebujeme udržovat *posloupnost* úprav, jako to dělá `synchronized`, stačí nám modifikátor **atributů** `volatile`. `volatile` je rychlejší (ale slabší) než `synchronized`. 192 | 193 | - `volatile` garantuje, že pokud nějaké vlákno do této proměnné zrovna zapisuje, jakékoli čtení této proměnné proběhne až poté, co zapisovací vlákno dokončí svou práci 194 | - každé vlákno tedy vždy vidí nejnovější verzi `volatile` proměnné 195 | - vhodné pro vztahy jeden writer, mnoho readerů 196 | 197 | Pokud potřebujeme, aby jedno vlákno čekalo na znamení, že se má spustit, od jiného vlákna, můžeme použí `wait` a `notify` (`notifyAll`). 198 | 199 | - `wait` pustí zámek současného objektu a suspeduje současné vlákno 200 | - `notifyAll` probudí všechna čekající vlákna, která poté mohou zkontrolovat, jestli už mají běžet (a buďto se spustí, nebo se zase suspendují přes `wait`) 201 | 202 | #### High level multithreading 203 | 204 | - jednodušší než se ručně starat o vlákna a mít jeden task (Runnable objekt) = jedno vlákno 205 | - používají se množiny dlouho existujících vláken (**thread pool**), z nichž každé dělá >1 task (nemusí se tak často rušit a zase vyrábět) 206 | - `FixedThreadPool` operuje s konstantním počtem vláken, zatímco `ForkJoinPool` se hodí pro rekurzivní problémy (buďto vyřeším problém na svém vlákně, nebo ho rozpůlíme mezi dvě) 207 | - počet dostupných jader je možno získat pomocí `Runtime.getRuntime().availableProcessors()` 208 | 209 | ### Abstraktní třídy 210 | 211 | - deklarovány pomocí `abstract class ...` 212 | - nelze z nich tvořit objekty, ale lze z nich dědit (jsou vlastně podobné interfacům) 213 | - mohou, ale nemusí, obsahovat abstraktní metody 214 | - mohou, ale nemusí obsahovat neabstraktní (běžné) metody 215 | 216 | Co jsou abstraktní metody? 217 | 218 | - abstraktní metody nemají implementaci (podobně jako např. metody v interfacu, tam ale nejsou označeny `abstract`) 219 | - jsou také označeny `abstract` 220 | - vždy musí být v abstraktní třídě 221 | 222 | Jak se tedy abstraktní třídy od interfaců liší? 223 | 224 | - mohou mít atributy, které nejsou `static` a `final` 225 | - v interfacech jsou implicitně obojí 226 | - mohou mít `public`, `protected`, i `private` konrétní (neabstraktní) metody 227 | - v interfacech jsou běžně všechny metody `public`, i když se jedná o `default` implementace 228 | - `private` metody byly do interfaců přidány v Javě 9 229 | 230 | ### Funkcionální interface a lambda výrazy 231 | 232 | - interface s právě jednou abstraktní metodou (SAM, single abstract method) 233 | - právě jedna SAM se dá ověřit s `@FunctionalInterface` 234 | - pokud má právě jednu abstraktní a spoustu defaultních, taky to projde 235 | - nesmí ani dědit další abstraktní z jiného interfacu 236 | - používá se jako *typ* pro lambda výrazy (anonymní funkce) 237 | - argumenty lambda výrazu musí odpovídat argumentům SAM 238 | - výsledný typ těla lambda výrazu musí odpovídat návratové hodnotě SAM 239 | 240 | ```java 241 | @FunctionalInterface 242 | interface Predicate { 243 | boolean isTrue(T a); // SAM 244 | } 245 | 246 | public class Main { 247 | public static void main(String[] args) { 248 | // input = čísla 0 až 9 249 | List input = IntStream.range(0, 10).boxed().collect(Collectors.toList()); 250 | System.out.println(filter(input, n -> n > 5)); 251 | // výsledek: [6, 7, 8, 9] 252 | // n -> n > 5 má typ Predicate, je automaticky zjištěný 253 | } 254 | 255 | // vrací prvky seznamu, pro které je predikát pravdivý 256 | static List filter(List list, Predicate pred) { 257 | ArrayList result = new ArrayList<>(); 258 | for (T a: list) { 259 | if (pred.isTrue(a)) { 260 | result.add(a); 261 | } 262 | } 263 | return result; 264 | } 265 | } 266 | ``` 267 | 268 | ## Zkouškové úlohy 269 | 270 | Jsou seřazeny podle tématu. 271 | 272 | 1. [Multithreading](#Multithreading) 273 | 2. [Třídy](#Třídy) 274 | 3. [Interfacy](#Interfacy) 275 | 4. [Lambda výrazy](#Lambda výrazy) 276 | 5. [Hodnoty proměnných](#Hodnoty proměnných) 277 | 6. [Triky](#Triky) 278 | 7. [Základní znalosti](#Základní znalosti) 279 | 8. [Výjimky](#Výjimky) 280 | 9. [Jednoduché úkoly na psaní kódu](#Jednoduché úkoly na psaní kódu) 281 | 282 | ### Multithreading 283 | 284 | Zpět na [Zkouškové úlohy](#Zkouškové úlohy). 285 | 286 | **Uvažujme následující třídu a předpokládejme, že nějaké vlákno získalo přístup a je uvnitř metody `setX(int, value)`. Pak jiným vláknem:** 287 | 288 | ```java 289 | public class A { 290 | private int x; 291 | 292 | public synchronized void setX(int value) { 293 | x = value; 294 | } 295 | 296 | public synchronized int getX() { 297 | return x; 298 | } 299 | } 300 | ``` 301 | 302 | 1. nelze pristupovat ani k `getX()` ani k `setX(int value)` 303 | 2. lze pristupovat k `getX()`, ale ne k `setX(int value)` 304 | 3. kod nelze prelozit, u metod nejsou deklarovany `throws` parametry 305 | 306 | *Odpověď:* [1] 307 | 308 | **Mějme následující třídu, co platí?** 309 | 310 | ```java 311 | class Test { 312 | public synchronized int foo() {...} 313 | public static synchronized void bar() {...} 314 | } 315 | ``` 316 | 317 | 1. `foo()` a `bar()`jsou pro přístup více vlákny vyloučeny každá sama se sebou i mezi sebou navzájem 318 | 2. `foo()` a `bar()` jsou pro přístup více vlákny vyloučeny každá sama se sebou, ale nikoliv mezi sebou navzájem 319 | 3. chyba překladu, nedeklaruje se výjimka `IllegalMonitorStateException` 320 | 321 | *Odpověď:* [2] 322 | 323 | Jedna metoda je static (používá zámek na třídě jako takové) a druhá není (používá zámek na instanci), proto nejsou navzájem vyloučené. 324 | 325 | **Co vypíše následující kód (pokud něco):** 326 | 327 | ```java 328 | public class Main { 329 | synchronized public void foo() { 330 | synchronized (this) { 331 | System.out.print("A"); 332 | synchronized (this) { 333 | System.out.print("B"); 334 | } 335 | } 336 | } 337 | public static void main(String[] args) { 338 | new Main().foo(); 339 | } 340 | } 341 | ``` 342 | 343 | 1. nepůjde přeložit, synchronized nelze napsat uvnitř metody 344 | 2. nic, vlákno se zablokuje 345 | 3. AB 346 | 347 | *Odpověď:* [3] 348 | 349 | Když metoda jednou získá zámek na objektu, tak už ho další bloky kódu v té metodě taky dostanou. 350 | 351 | **Která definice `s` je možná, aby se dal kód přeložit?** 352 | 353 | ```java 354 | synchronized (s) { 355 | /* ... */ 356 | } 357 | ``` 358 | 359 | 1. `synchronized` se takto nedá použít 360 | 2. `Thread s = new Thread(); ` 361 | 3. `Object s = new Object(); ` 362 | 4. `String s = "Hello"; ` 363 | 5. `int s = 100; ` 364 | 6. `Runnable s = () -> {}; ` 365 | 366 | *Odpověď*: [2, 3, 4, 6] Za `s` je možno dosadit jakýkoli objekt. 367 | 368 | **Doplňte deklaraci hashTable tak, aby obsahovala základní sémantiku hash tabulky — metody `V get (K key)` a `void put(K key, V value)`. Navíc k objektu musí bezpečně přistupovat více vláken najednou (tedy volání metod více vlákny najendou je vyloučeno). Můžete si definovat libovolné další třídy nebo použít cokoliv ze standardní knihovny.** 369 | 370 | Metody `get` a `put` by obě měly být `synchronized`, zbytek je jednoduchý. 371 | 372 | ### Třídy 373 | 374 | Zpět na [Zkouškové úlohy](#Zkouškové úlohy). 375 | 376 | **Upravte následující kód tak, aby se zkompiloval:** 377 | 378 | ```java 379 | public class Class { 380 | abstract void foo(); 381 | } 382 | ``` 383 | 384 | *Řešení*: 385 | 386 | ```java 387 | public abstract class Class { 388 | abstract void foo(); 389 | } 390 | ``` 391 | 392 | Abstraktní metody musí být v abstraktní třídě. 393 | 394 | **Mějme abstraktní třídu, pak:** 395 | 396 | 1. od ní nelze vytvářet instance 397 | 2. lze od ni dědit, ale nelze předefinovat žádnou její metodu 398 | 3. nelze od ni dědit 399 | 4. všechny jeji metody jsou také abstraktní 400 | 401 | *Odpověď:* [1] 402 | 403 | **Jaký modifier může mít vnitřní (inner) třída?** 404 | 405 | 1. public 406 | 2. private 407 | 3. static 408 | 4. friendly 409 | 5. volatile 410 | 411 | *Odpověď:* [1, 2, 3] 412 | 413 | **Co je pravda?** 414 | 415 | 1. vnitřní třídy musí implementovat alespoň jeden interface 416 | 2. vnitřní třídy mají přístup ke všem (i private) elementům třídy, která je obsahuje 417 | 3. vnitřní třídy nedědí od třídy `Object` 418 | 4. vnitřní třídy dědí od té vnější 419 | 420 | *Odpověď*: [2] 421 | 422 | **O jakékoliv třídě Enum platí:** 423 | 424 | 1. nemůže mít konstruktor 425 | 2. není potomkem žádné třídy 426 | 3. dědí od `java.lang.Enum ` 427 | 4. nemůže obsahovat žádné metody 428 | 5. může obsahovat `public static void main(String[] args) ` 429 | 430 | *Odpověď:* [3, 5] 431 | 432 | **Co vypíše (pokud něco) kód:** 433 | 434 | ```java 435 | class A { 436 | static int x = 1; 437 | } 438 | 439 | public class Main { 440 | static A a = null; 441 | public static void main(String[] args) { 442 | System.out.println(a.x); 443 | } 444 | } 445 | ``` 446 | 447 | 1. 0 448 | 2. 1 449 | 3. pokažé něco jiného (závisí na okolnostech) 450 | 4. spadne na NullPointerException 451 | 5. nelze přeložit 452 | 453 | *Odpověď:* [2] 454 | 455 | U statického atributu *null* nevadí. Navíc statické atributy lze volat i na instancích třídy, nejen na třídě samé. 456 | 457 | **Co vypíše (pokud něco) kód:** 458 | 459 | ```java 460 | class A { 461 | int x = 1; 462 | } 463 | 464 | class B extends A { 465 | int x = 2; 466 | public void foo() { 467 | System.out.println(this.x); 468 | System.out.println(super.x); 469 | System.out.println(((A)this).x); 470 | } 471 | public static void main(String[] args) { 472 | B b = new B(); 473 | b.foo(); 474 | } 475 | } 476 | ``` 477 | 478 | 1. 2 2 2 479 | 2. 2 2 1 480 | 3. 2 1 2 481 | 4. 2 1 1 482 | 5. chyba překladu, this nejde přetypovat 483 | 6. chyba překladu, super není na proměnné 484 | 485 | *Odpověď:* [4] Viz také [otázka na stack overflow](https://stackoverflow.com/questions/60065506/inherited-attribute-method-static-method-behavior/60065829?noredirect=1#comment106242033_60065829). 486 | 487 | **Co se vypíše?** 488 | 489 | ```java 490 | public class A { 491 | public static void foo() { System.out.println("A"); } 492 | } 493 | 494 | public class B extends A { 495 | public static void foo() { System.out.println("B"); } 496 | } 497 | 498 | public class Main { 499 | public static void main(String[] args){ 500 | A a = new B(); 501 | a.foo(); 502 | } 503 | } 504 | ``` 505 | 506 | 1. A 507 | 2. B 508 | 3. nelze určit 509 | 510 | *Odpověď*: [1] 511 | 512 | Protože voláme **statickou** funkci `foo`, ta se dívá pouze na typ `a` a to je `A` (jinými slovy, není *virtualizovaná*) Zavolá se tedy `A.foo()`. Kdyby se nejednalo o statickou funkci, zavolalo by se `foo()` od objektu `a`, který je reálně ze třídy `B`. 513 | 514 | **Rozhodněte, co bude na standardním výstupu po spuštění programu:** 515 | 516 | ```java 517 | class A { 518 | int x = 1; 519 | } 520 | 521 | class B extends A { 522 | int x = 2; 523 | 524 | public void foo() { 525 | System.out.println(this.x); 526 | System.out.println(super.x); 527 | } 528 | 529 | public static void main(String[] args) { 530 | B b = new B(); 531 | b.foo(); 532 | } 533 | } 534 | ``` 535 | 536 | 1. 2 2 537 | 2. 1 1 538 | 3. 2 1 539 | 4. nelze aplikovat klicove slovo ***super*** na atributy 540 | 5. nelze prepisovat atributy tridy, od ktere se dedi 541 | 542 | *Odpověď:* [3] Podobné jako otázka výše. Tomuto se říká *field hiding*. 543 | 544 | **Co se vypíše?** 545 | 546 | ```java 547 | class MyClass{ 548 | public static int i = 0; 549 | 550 | public MyClass() { 551 | i++; 552 | } 553 | 554 | public static void main(String[] args) { 555 | MyClass[] my = new MyClass[5]; 556 | for(int i = 0; i < 5; i++){ 557 | my[i] = new MyClass(); 558 | } 559 | System.out.println(i); 560 | } 561 | } 562 | ``` 563 | 564 | 1. 0 565 | 2. 1 566 | 3. 4 567 | 4. 5 568 | 5. Nelze určit 569 | 570 | *Odpověď*: [4] 571 | 572 | Vypíše se 5, protože při každém zavolání `new MyClass()` se ke statickému atributu `i` přičte jednička. Protože je atribut statický, jedná se vždy o stejné `i` (netvoří se pro každý `new MyClass` objekt zvlášť). 4 by se vypsalo v případě, že bychom vypisovali `i` z for loopu, to ale mimo loop neexistuje. 573 | 574 | **Co vypíše následující kód (pokud něco):** 575 | 576 | ```java 577 | class A { 578 | public A() { 579 | super(); 580 | System.out.print("A"); 581 | } 582 | } 583 | class B extends A { 584 | public B() { 585 | super(); 586 | System.out.print("B"); 587 | } 588 | } 589 | class C extends B { 590 | public C() { 591 | System.out.print("C"); 592 | } 593 | } 594 | public class Main { 595 | public static void main(String[] args) { 596 | C c = new C(); 597 | } 598 | } 599 | ``` 600 | 601 | 1. nepůjde přeložit, konstruktor třídy A volá super() ale přitom nemá explicitně definovaného předka 602 | 2. C 603 | 3. ABC 604 | 605 | *Odpověď:* [3] 606 | 607 | `super()` se totiž z konstruktoru volá implicitně, a každá třída implicitně extenduje `Object` (nebo explicitně nějakou jeho podtřídu) 608 | 609 | ### Interfacy 610 | 611 | Zpět na [Zkouškové úlohy](#Zkouškové úlohy). 612 | 613 | **Co platí o rozhraních (*interface*):** 614 | 615 | 1. třída může implementovat nejvýše jeden interface 616 | 2. třída může implementovat žádný, jeden nebo i více interfaces 617 | 3. interface může implementovat nejvýše jedna třída 618 | 4. interface může dědit od nejvýše jednoho interface 619 | 5. interface může dědit od žádného, jednoho nebo i více interfaces 620 | 621 | *Odpověď:* [2, 5] 622 | 623 | **Co se stane s následujícím kódem?** 624 | 625 | ```java 626 | interface A { 627 | default void hello() { System.out.println("Hello A"); } 628 | } 629 | 630 | interface B { 631 | default void hello() { System.out.println("Hello B"); } 632 | } 633 | 634 | class C implements A, B { } 635 | ``` 636 | 637 | 1. nepřeloží se nic 638 | 2. přeloží se A, B nepřeloží se C 639 | 3. nepřeloží se A ani B, ale C ano 640 | 641 | *Odpověď:* [2] 642 | 643 | C má metodu s dvěma implementacemi a neví, kterou si vybrat. Správně by mělo `hello()` být v C overridnuté a implementované znovu. 644 | 645 | **Která tvrzení jsou správná?** 646 | 647 | ```java 648 | /* soubor A.java */ 649 | public interface A { 650 | void foo(int i); 651 | default void bar() { 652 | foo(0); 653 | } 654 | } 655 | 656 | /* soubor B.java */ 657 | public class B implements A { 658 | public void foo( int i) { 659 | System.out.println( i); 660 | } 661 | public void bar() { 662 | System.out.println("Hello"); 663 | } 664 | } 665 | ``` 666 | 667 | 1. Obojí se přeloží bez chyb 668 | 2. A se nepřeloží, z defaultní metody se nedá volat nedefaultní 669 | 3. A se přeloží bez chyby, ale v B je chyba: defaultní metody z interface se nedají předefinovat 670 | 4. A se přeloží bez chyby, ale v B je chyba: před přepsáním metody `bar` chybí klíčové slovo `default` 671 | 672 | *Odpověď*: [1] 673 | 674 | Defaultní implementace je pouze "záloha" v případě, že metoda není implementována ve třídě. 675 | 676 | **Co se vypíše?** 677 | 678 | ```java 679 | interface Iface { 680 | default void foo() { System.out.println("Interface"); } 681 | } 682 | 683 | class A { 684 | public void foo() { System.out.println("Class"); } 685 | } 686 | 687 | class B extends A implements Iface { 688 | public static void main(String[] args) { 689 | B b = new B(); 690 | b.foo(); 691 | } 692 | } 693 | ``` 694 | 695 | 1. Interface 696 | 2. Class 697 | 3. Nevypíše se nic 698 | 4. Nepůjde přeložit 699 | 700 | *Odpověď*: [2] 701 | 702 | ### Lambda výrazy 703 | 704 | Zpět na [Zkouškové úlohy](#Zkouškové úlohy). 705 | 706 | **Máme definované `Callable`, `Supplier` a `Predicate`. Která z následujících přiřazení lamda výrazu jsou správná (kompilátor je přeloží):** 707 | 708 | ```java 709 | interface Callable { 710 | T call(); 711 | } 712 | 713 | interface Supplier { 714 | T get(); 715 | } 716 | 717 | interface Predicate{ 718 | boolean test(T t); 719 | } 720 | ``` 721 | 722 | 1. `Supplier su = () -> { return true; };` 723 | 2. `Callable sa = () -> { return true; };` 724 | 3. `Predicate pr = () -> { return true; };` 725 | 726 | *Odpověď*: [1, 2] `Predicate` potřebuje jeden argument. 727 | 728 | **Do následujícího kódu doplňte do parametru metody map lambda výraz tak, aby výstupní stream obsahoval délky řetězců ve vstupním streamu.** 729 | 730 | ```java 731 | List list = ...; 732 | Stream st = list.stream().map(); 733 | ``` 734 | 735 | *Řešení:* 736 | 737 | ```java 738 | Stream st = list.stream().map(s -> s.length); 739 | ``` 740 | 741 | **Metoda `static void sort( T[] array, Comparator c)` setřídí pole `array` a použije k tomu komparátor `c`. Doplňte do následujícího kódu implementeaci komparátoru lambda vyrázem tak, aby třídil řetězce podle délky.** 742 | 743 | ```java 744 | interface Comparator { 745 | int compare(T o1, T o2); 746 | } 747 | 748 | String[] strings = new String[1000]; 749 | /* setup kód */ 750 | 751 | Comparator comparator = ; 752 | sort(strings, comparator); 753 | ``` 754 | 755 | *Řešení:* 756 | 757 | ```java 758 | Comparator comparator = (s1, s2) -> s1.length - s2.length; 759 | ``` 760 | 761 | **Máme následující kód. Doplňte do `forEach` výraz tak, aby se vypsaly všechny prvky seznamu.** 762 | 763 | ```java 764 | interface Consumer { 765 | void accept(T t); 766 | } 767 | 768 | void forEach(Consumer action) { ... } // hlavička 769 | 770 | List list = ...; 771 | list.stream.forEach(); 772 | ``` 773 | 774 | *Řešení*: 775 | 776 | ```java 777 | list.stream.forEach(a -> System.out.println(a)); 778 | ``` 779 | 780 | ### Hodnoty proměnných 781 | 782 | Zpět na [Zkouškové úlohy](#Zkouškové úlohy). Viz [Literály](#Literály). 783 | 784 | **Atribut (= field, pozn. Evžena) typu `int` bez explicitní inicializace:** 785 | 786 | 1. je inicializován hodnotou 0 787 | 2. má nedefinovanou hodnotu a při čtení je vráceno předem nestanovitelné číslo 788 | 3. má nedefinovanou hodnotu a při čtení je vyvolána výjimka typu UndefinedValueException 789 | 4. má nedefinovanou hodnotu a překladač nedovolí použití, dokud není jisté, že se napřed nějaká hodnota nastaví. 790 | 5. je inicializován maximální hodnotou, která se do typu int vejde 791 | 792 | *Odpověď:* [1] 793 | 794 | Atribut je defaultně 0 (případně *false* nebo *null*, podle typu), ale kdyby se jednalo o proměnnou v metodě, neprojde to přes kompilaci. 795 | 796 | **Co se nepřeloží?** 797 | 798 | 1. `byte x = 1024; ` 799 | 2. `int x = 08; ` 800 | 3. `long x = null; ` 801 | 4. `char x = "a"; ` 802 | 5. `int x = 0b01; ` 803 | 804 | *Odpověď*: [1, 2, 3, 4] Viz část o literálech výše. 805 | 806 | **Lokální proměnná typu `int` vyskytující se uvnitř metody:** 807 | 808 | 1. je od mista deklarace inicializovana hodnotou 0 809 | 2. ma nedefinovanou hodnotu a pri cteni je vraceno predem nestanovitelne cislo 810 | 3. ma nedefinovanou hodnotu a prekladac nedovoli pouziti 811 | 4. je inicializovana maximalni hodnotou, ktera se do typu int vejde 812 | 813 | *Odpověď:* [3] viz otázka výše, ale naopak. 814 | 815 | **Co se nezkompiluje?** 816 | 817 | 1. `System.out.println(1+1);` 818 | 2. `int x = 42 + '25';` 819 | 3. `String s = "foo" + 'bar';` 820 | 4. `byte x = 255;` 821 | 822 | *Odpověď:* [2, 3, 4] 823 | 824 | Mezi `''` musí být `char` (tj. jeden znak) a `byte` má rozsah -128 až 127. 825 | 826 | **Co jde přiřadit do proměnné typu boolean?** 827 | 828 | *Odpověď:* pouze `true` a `false` 829 | 830 | **Co se nepřeloží?** 831 | 832 | 1. `int i = 1234_5678; ` 833 | 834 | 2. `double d = 3.14_15; ` 835 | 836 | 3. `int j = 0x12_ab_12; ` 837 | 838 | 4. `int k = null; ` 839 | 840 | 5. `boolean b = 0; ` 841 | 842 | 6. ```java 843 | char c = ' 844 | '; 845 | ``` 846 | 847 | *Odpověď*: [4, 5, 6] Viz literály. 848 | 849 | **Co se vypíše?** 850 | 851 | ```java 852 | Integer i1 = 5; 853 | int i2 = i1; 854 | i1 += 1; 855 | System.out.println(i1); 856 | System.out.println(i2); 857 | ``` 858 | 859 | 1. 5 5 860 | 2. 5 6 861 | 3. 6 5 862 | 4. 6 6 863 | 5. nic 864 | 865 | *Odpověď*: [3] 866 | 867 | Do `i2` se uloží (zkopíruje) pouze unwrapovaná hodnota z `i1`; změna `i1` tedy `i2` neovlivní. 868 | 869 | ### Triky 870 | 871 | Zpět na [Zkouškové úlohy](#Zkouškové úlohy). 872 | 873 | **Lze napsat deklaraci proměnné `i` tak, aby následující 874 | cyklus byl nekonečný?** 875 | 876 | ```java 877 | while (i != i ) {} // 1. 878 | while (i != i + 0) {} // 2. 879 | while (i <= j && j <= i && i != j) {} // 3. 880 | ``` 881 | 882 | *Odpovědi:* 883 | 884 | 1. `i = Double.NaN`, protože `NaN` se nerovná ničemu. 885 | 886 | 2. `i = ""`, stringy lze sčítat s čísly, číslo se převede na string 887 | 3. `i = new Integer(1)` a `j = new Integer(1)`, jejich porovnání poté porovnává reference 888 | 889 | **Příkazem `import static ...` lze naimportovat do lokálního jmenného prostoru:** 890 | 891 | 1. všechny atributy a metody třídy 892 | 2. pouze statické atributy třídy 893 | 3. pouze statické metody třídy 894 | 4. pouze statické metody a statické atributy třídy 895 | 5. pouze atributy a metody označené anotací ``@exportStatic`` 896 | 897 | *Odpověď:* [4] 898 | 899 | Analogicky k běžnému `import`, který importuje třídy z balíků, `import static` importuje statické věci ze tříd. 900 | 901 | **Výstupem násedujícího úseku kódu?** 902 | 903 | ```java 904 | public class A { 905 | public int x = 0; 906 | 907 | // [pozn. Evžena] toto je ta zajímavá část 908 | { 909 | x += 1; 910 | } 911 | // konec zajímavé části 912 | 913 | public A() { 914 | x += 1; 915 | } 916 | 917 | public static void main(String[] args) { 918 | A a = new A(); 919 | System.out.println(a.x); 920 | } 921 | } 922 | ``` 923 | 924 | 1. nelze přelozit 925 | 2. 0 926 | 3. 1 927 | 4. 2 928 | 5. hodnota se můze lišit při opakovaném spuštění programu 929 | 930 | *Odpověď:* [4] 931 | 932 | Jedná se o tzv. *inicializační blok*. Je to blok kódu, který proběhne při každém vytvoření objektu od dané třídy, a to *před* konstruktorem. Inicializačních bloků může mít třída více, poté jsou spuštěny odshora jeden po druhém (a po nich teprve konstruktor). 933 | 934 | **Napište deklaraci proměnné `x` tak, aby po provedení `x = x + 0 `neměla původní hodnotu. Pokud to nejde, zdůvodněte. ** 935 | 936 | *Řešení:* 937 | 938 | ```java 939 | String x = ""; 940 | x = x + 0; // x je "0" 941 | ``` 942 | 943 | **Máme kolekci `ArrayList`. Které přiřazení se přeloží bez chyby?** 944 | 945 | 1. `Collection co = new ArrayList(); ` 946 | 2. `Collection co = new ArrayList(); ` 947 | 3. `Collection co = new ArrayList(); ` 948 | 4. `Collection co = new ArrayList<>(); ` 949 | 5. `Collection co = new ArrayList(); ` 950 | 951 | *Odpověď*: [1, 4, 5] 952 | 953 | Přiřazení vlastně tvrdím, že věc napravo má stejný typ jako věc nalevo. Proto můžu vždy přiřazovat do stejného anebo obecnějšího typu, například `Object a = "a"` je v pohodě, protože každý `String` je i `Object`. 954 | 955 | Stejně tak platí, že každý `ArrayList` je i `Collection` (odpovědi 1, 4, 5 — `?` znamená "jakýkoli typ"). Ovšem, o vztahu `Collection` a `ArrayList` nevíme nic (odpovědi 2, 3). 956 | 957 | Pro zajímavost, druhý a třetí bod by šly opravit přidáním otazníku: 958 | 959 | ```java 960 | // ~ String 961 | Collection co = new ArrayList(); 962 | // ~ Object 963 | Collection co = new ArrayList(); 964 | ``` 965 | 966 | **Napište metodu `void copy(seznamA, seznamB)` (hlavička je pouze přibližná), která zkopíruje prvky seznamu A do seznamu B pomocí metod `T get(int i)` a `void add(T element)` (kde T je typová proměnná). Pozor, seznam A může obsahovat jiné typy než seznam B, vždy ale takové, aby kopírování bylo možná (např. seznam A bude `List` a seznam B `List`).** 967 | 968 | *Řešení:* 969 | 970 | ```java 971 | public static void copy(List a, List b) { 972 | for (T item: a) { 973 | b.add(a); 974 | } 975 | } 976 | ``` 977 | 978 | Nejdůležitější je hlavička, kde se používá `` (deklarování toho, že hodláme použít typovou proměnnou) a poté `?`. Otazník značí "jakýkoli typ" a `? extends T` znamená "jakýkoli typ, který je podtřídou T", kde `T` je obsah druhého seznamu. Akceptovalo se i (o trochu horší) řešení se `super`, které funguje analogicky: 979 | 980 | ```java 981 | public static void copy(List a, List b) { ... } 982 | ``` 983 | 984 | ### Základní znalosti 985 | 986 | Zpět na [Zkouškové úlohy](#Zkouškové úlohy). Většinou jsou pokryty v kapitolách výše, nebo se jedná o jednoduché věci jako "equals u objektů". 987 | 988 | **Kam lze napsat `abstract`?** 989 | 990 | *Odpověď:* Jen před třídu a metodu. 991 | 992 | **Co je obsahem pole `args` v metodě `main`?** 993 | 994 | *Odpověď:* Pouze argumenty, které byly programu předány (tedy `args[0]` není jméno samotného programu, jako tomu je např. v shellu nebo C#). 995 | 996 | **Není-li u prvku třídy (metoda, atribut, ...) uveden žádný modifikátor viditelnosti (public, private, ...), je tento prvek viditelný:** 997 | 998 | 1. pouze z této třídy 999 | 2. pouze z této třídy a potomků této třídy 1000 | 3. pouze ze stejného balíku 1001 | 4. pouze ze stejného balíku a potomků této třídy 1002 | 5. odkudkoliv 1003 | 1004 | *Odpověď:* [3] 1005 | 1006 | **Která slova jsou klíčová?** 1007 | 1008 | 1. throw 1009 | 2. throws 1010 | 3. class 1011 | 4. array 1012 | 5. namespace 1013 | 6. method 1014 | 1015 | *Odpověď*: [1, 2, 3] Viz klíčová slova. 1016 | 1017 | **Co se vypíše?** 1018 | 1019 | ```java 1020 | int i = 9; 1021 | switch (i) { 1022 | default: System.out.println("default"); 1023 | case 0: System.out.println("nula"); 1024 | break; 1025 | case 1: System.out.println("jedna"); 1026 | break; 1027 | case 2: System.out.println("dva"); 1028 | break; 1029 | } 1030 | ``` 1031 | 1032 | *Odpověď:* *default nula* 1033 | 1034 | Za defaultem není `break`, takže poté, co matchne, se pokračuje v tělech casů dokud nepřijde break. 1035 | 1036 | **Co může v následujícím kódu být místo `/* modifier */`?** 1037 | 1038 | ```java 1039 | public class MyClass { 1040 | /* modifier */ void foo() {} 1041 | } 1042 | ``` 1043 | 1044 | 1. `public` 1045 | 2. `final` 1046 | 3. `static` 1047 | 4. `friendly` 1048 | 5. `volatile` 1049 | 6. `override` 1050 | 1051 | *Odpověď*: [1, 2, 3] `volatile` je pouze pro atributy, `friendly` a `override` nejsou klíčová slova. 1052 | 1053 | **Co se stane při překládání?** 1054 | 1055 | ```java 1056 | class MyClass { 1057 | public static void main(String[] args) { 1058 | amethod(args); 1059 | } 1060 | public void amethod(String arguments[]) { 1061 | System.out.println(arguments[1]); 1062 | System.out.println(arguments); 1063 | } 1064 | } 1065 | ``` 1066 | 1067 | 1. nelze přeložit - metoda `amethod` není deklarována před voláním 1068 | 2. nelze přeložit - statická metoda `main` volá instanční metodu `amethod` 1069 | 3. nelze přeložit - špatná deklarace pole v `main` 1070 | 4. nelze přeložit - `println` nepřijímá jako parametr pole 1071 | 1072 | *Odpověď*: [2] 1073 | 1074 | **Co se přeloží?** 1075 | 1076 | ```java 1077 | if (3 == 2) System.out.println("Hi!"); // 1 1078 | if (3 = 2) System.out.println("Hi!"); // 2 1079 | if (true) System.out.println("Hi!"); // 3 1080 | if (3 != 2) System.out.println("Hi!"); // 4 1081 | if ("abcd".equals("abcd")) System.out.println("Hi!"); // 5 1082 | ``` 1083 | 1084 | *Odpověď*: [1, 3, 4, 5] 1085 | 1086 | ### Výjimky 1087 | 1088 | Zpět na [Zkouškové úlohy](#Zkouškové úlohy). Viz [Výjimky — teorie](#Výjimky — teorie). 1089 | 1090 | **Které výjimky je nutné odchytit nebo deklarovat?** 1091 | 1092 | 1. všechny 1093 | 2. potomky `java.lang.Error ` 1094 | 3. potomky `java.lang.Exception` 1095 | 4. potomky `java.lang.RuntimeException` 1096 | 5. žádné 1097 | 1098 | *Odpověď:* [3] 1099 | 1100 | Samozřejmě kromě potomků `RuntimeException`, kteří jsou technicky také potomci `Exception`. 1101 | 1102 | **Co je správná deklarace?** 1103 | 1104 | 1. `void foo(void) throws MyException { } ` 1105 | 2. `void foo() throws MyException { } ` 1106 | 3. `void foo() throws { } MyException ` 1107 | 4. `foo() throw MyException { } ` 1108 | 1109 | *Odpověď:* [2] 1110 | 1111 | **Co může být v následujícím kódu místo `/* type of exception */`?** 1112 | 1113 | ```java 1114 | class MyException extends java.lang.Exception {} 1115 | 1116 | public class A { 1117 | public void foo(int i) throws MyException { 1118 | if (i < 0) 1119 | throw new /* type of exception */(); 1120 | } 1121 | } 1122 | ``` 1123 | 1124 | 1. `MyException` 1125 | 2. `java.lang.Exception` 1126 | 3. `java.lang.Error` 1127 | 4. `java.lang.RuntimeException` 1128 | 5. `java.lang.Throwable` 1129 | 6. `java.io.IOException` 1130 | 1131 | *Odpověď*: [1, 3, 4] 1132 | 1133 | `Error` a `RuntimeException` je možno vyhodnit kdykoli i bez předchozí deklarace v `throws`. 1134 | 1135 | **Napište program, který překopíruje jeden soubor do druhého. Ošetřete všechny výjimky.** 1136 | 1137 | Následující kód nemá vše potřebné, ale základ lze poznat. 1138 | 1139 | ```java 1140 | try (InputFileStream ifs = ... ; OutputFileStream ofs = ...;) { 1141 | char c; 1142 | while((c = ifs.read()) != -1) { 1143 | ofs.write(c); 1144 | } 1145 | } catch (IOException ex) { 1146 | System.out.println(ex.getMessage()); // ifs a ofs se zavřou samy díky try/with 1147 | } 1148 | ``` 1149 | 1150 | ### Jednoduché úkoly na psaní kódu 1151 | 1152 | První dvě řešení jsou převzata z [Matfiz: Java](http://mff.lokiware.info/Java?v=i1q&fbclid=IwAR0JPmCV24V1GZAKSYkjeIdNf38-U2z75Q5N3TyHZVpoH_7A6_E-JsAIwwA). Zbytek se týká většinou nějakého jednoduchého chytáku typu `equals` u stringů. Zpět na [Zkouškové úlohy](#Zkouškové úlohy). 1153 | 1154 | **Napište metodu, která má dva parametry typu `int`, *hrubou mzdu* a *daň v procentech*, a vrací hodnotu typu `double` udávající daň k zaplacení. Ověřte, že daň je v rozmezí 0–100 a mzda je nezáporná, pokud parametry nejsou v pořádku vyhoďte výjimku `MyException`, která je přímým potomkem `java.lang.Exception` (předpokládá se, že je deklarovaná a importovaná).** 1155 | 1156 | *Řešení:* 1157 | 1158 | ```java 1159 | public class TaxCalculator{ 1160 | /* MyException je přímý potomek java.lang.Exception => je třeba deklarovat: */ 1161 | public double calculateTax(int gross, int taxPercentage) throws MyException{ 1162 | if( gross < 0 || taxPercentage < 0 || taxPercentage > 100 ) 1163 | throw new MyException(); 1164 | /* Pro FP aritmetiku je třeba buď přetypovat nebo použít FP konstantu (tady 100.0): */ 1165 | return gross * (taxPercentage/100.0); 1166 | } 1167 | } 1168 | ``` 1169 | 1170 | **Napište třídu pro dynamické pole hodnot typu `int`. Implementujte jen metody pro přidání prvku na konec pole `void add(int x)` a získání hodnoty prvku `int get(int i)` (v případě chybného indexu by měla vyvolat výjimku). Pro implementaci použijte skutečné pole hodnot typu `int`, které se podle potřeby dynamicky realokuje.** 1171 | 1172 | *Řešení:* 1173 | 1174 | ```java 1175 | public class DynamicArray{ 1176 | private int[] intArray = new int[0]; // Nejsnažší řešení (netřeba ošetřovat hodnotu null a/nebo vyhazovat výjimky). 1177 | public int get(int i){ 1178 | /* 1179 | * Následující přístup může vyhodit ArrayIndexOutOfBoundsException, 1180 | * kterou nemá smysl zachytávat jen, abychom ji opět vyhodili. 1181 | * Jedná se o runtime exception, takže se ani nedeklaruje v hlavičce. 1182 | */ 1183 | return intArray[i]; 1184 | } 1185 | public void add(int x){ 1186 | /* 1187 | * Místo ručního kopírování lze použít: 1188 | * - java.lang.System.arraycopy(), 1189 | * nebo ještě lépe: 1190 | * - java.util.Arrays.copyOf(), 1191 | * ale to bych asi u zkoušky nedělal, neb si nepamatuju pořadí parametrů. 1192 | */ 1193 | int[] intArrayX = new int[intArray.length + 1]; // (zvýšení jen o 1 je na implementaci nejjednodušší) 1194 | int i = 0; 1195 | for(int a : intArray) 1196 | intArrayX[i++] = a; 1197 | intArrayX[i] = x; 1198 | intArray = intArrayX; 1199 | } 1200 | } 1201 | ``` 1202 | 1203 | **Máme `class Pair { String key; int value; }`, napište metodu `Pair[] find(String key, Pair[] items)`, která vrátí všechny páry z `items`, které mají stejný klíč jako ten daný.** 1204 | 1205 | Pozor na porovnávání stringů přes `.equals()`. 1206 | 1207 | **Napište metodu, která v daném seznamu spočítá osoby alespoň tak staré, jak je zadáno v argumentu parametrem `age`. Osoby s neplatným jménem (`null` nebo `""`) do hledání nezahrnujte.** 1208 | 1209 | ```java 1210 | class Person { String name; int age; } 1211 | ``` 1212 | 1213 | *Řešení:* 1214 | 1215 | ```java 1216 | public static int countOlder(Person[] list, int age) { 1217 | return 1218 | (int) Arrays.stream(list) 1219 | .filter(p -> p.name != null) 1220 | .filter(p -> !p.name.equals("")) 1221 | .filter(p -> p.age >= age) 1222 | .count(); // .count() vrací long, proto na začátku ten cast do (int) 1223 | } 1224 | ``` 1225 | 1226 | Dá se samozřejmě řešit i for-loopem. Důležité je nejprve odstranit lidi s `null` jménem, protože jinak bychom kontrolovali `null.age` nebo `null.name.equals("")` a spadlo by nám to. Stringy porovnáváme s ``.equals()`. Dobré je také vědět, že `filter` z původního streamu vybere prvky, které *splňují* uvedenou podmínku (má tedy trochu neintuitivní jméno). 1227 | 1228 | **Napište metodu, která vrátí řetězec obsahující n-krát řetězec, který bere v parametru. Např. pro `3` a `"Hello"` vrátí `"HelloHelloHello"`:** 1229 | 1230 | ```java 1231 | public static String repeat(String s, int n) { 1232 | StringBuilder sb = new StringBuilder(s); 1233 | for (int i = 0; i < n; i++) { 1234 | sb.append(s); 1235 | } 1236 | return sb.toString(); 1237 | } 1238 | ``` 1239 | 1240 | Použití `StringBuilder` místo přičítání stringů. 1241 | 1242 | **Napište metodu, která vytiskne obsah jakékoliv kolekce (jako parametr bere instanci typu `Collection` nebo jakéhokoli jejího podtypu a objekty v ní jsou definovány jakýmkoliv typem mezi špičatými závorkami).** 1243 | 1244 | *Řešení:* 1245 | 1246 | ```java 1247 | void print(Collection items) { 1248 | items.stream().forEach(i -> System.out.println(i)); 1249 | } 1250 | ``` 1251 | 1252 | **Doplňte metodu tak, aby vracela počet osob s daným křestním jménem narozených v daném roce. Nezapomeňte otestovat, zda předané parametry nejsou `null` atd.** 1253 | 1254 | ```java 1255 | class Person { String firstname; String surname; int yearOfBirth; } 1256 | ``` 1257 | 1258 | *Řešení:* 1259 | 1260 | ```java 1261 | public static int count(Person[] array, int year, String name) { 1262 | if (array == null) { return 0; } 1263 | return 1264 | (int) Arrays.stream(array) 1265 | .filter(p -> p.firstname.equals(name) && p.yearOfBirth == year) 1266 | .count() 1267 | } 1268 | ``` 1269 | 1270 | **Definujte korektní `equals()` v následující třídě:** 1271 | 1272 | ```java 1273 | class Complex { 1274 | int re; 1275 | int im; 1276 | } 1277 | ``` 1278 | 1279 | *Řešení*: 1280 | 1281 | ```java 1282 | class Complex { 1283 | int re; int im; 1284 | 1285 | @Override 1286 | public boolean equals(Object other) { 1287 | if (other instanceof Complex) { 1288 | Complex that = (Complex) other; 1289 | return this.re == that.re && this.im == that.im; 1290 | } 1291 | return false; 1292 | } 1293 | } 1294 | ``` 1295 | 1296 | Musíme zkontrolovat, že je `other` stejná třída pomocí `instanceof` a potom teprve můžeme porvnávat. 1297 | 1298 | --------------------------------------------------------------------------------