Objekty a třídy
Materiály
- The Java Tutorial: Object-Oriented Programming Concepts
- The Java Tutorial: Classes and Objects
- The Java Tutorial: Interfaces and Inheritance
- Java in a Nutshell, 6th Edition. A Desktop Quick Reference, 2014, strany 66–134
Třídy
O třídách bychom mohli řící, že jsou šablonou, která definuje vlastnosti a chování určité skupiny objektů.
V Javě každá třída musí být umístěna v samostatném souboru a tento soubor musí mít stejný název jako třída
v něm obsažená. Vysvětleno na příkladu; třída Bar
musí být v souboru Bar.java
.
Každá třída musí být obsažena v baličku, který určuje cestu ke třídě a také slouží jako jmenný prostor.
Příklad java.lang.String
a cz.upol.zp3jv.String
.
//Jméno třídy začíná velkým písmenem a stejně tak každé další slovo.
//V názvech není dovoleno používat _ nebo -
class Bar {
//Definice atributů
//Konstruktory
//Metody
}
Atributy
Atributy definují vnitřní stav objektu.
<viditelnost> <modifikátory> <typ> <název> [= inicializační hodnota] ;
Viditelnost
private
- Viditelný pouze ve třídě, kde je atribut deklarován.protected
- Viditelný ve třídě, kde je atribut deklarován, dědicí třídě a ve třídách které jsou ve stejném balíčku.public
- Viditelný z jakékoliv třídy
Ve většině případů jsou atributy deklarovány jako private a pro přístup se využívají gettery a settery (viz níže).
Modifikátory
static
- Atribut sdílený všemi instancemi.final
- Konstanta.
Typ
Určuje datový typ atributu: int
, String
, ...
Název
Název atributu začíná malým pismenem a každé další slovo začíná velkým písmenem. Pokud je atribut konstanta všechny znaky jsou psány velým písmem a slova se oddělují _.
Konstruktory
Konstruktory slouží pro vytvoření objektu dané třídy. Jejich syntaxe je podobná metodám jejich název je ale totožný s názvem třídy a nemají návratový typ.
<viditelnost> <název třídy> (typ1 argument1, typ2 argument2, ..., typN argumentN) { super(argument1, ...); // Zavolání rodičovského kontruktoru // Inicializace proměných }
Metody
Metody definují chování objektu. Důležité metody jsou gettery a settery pro jednotlivé atributy. Zajistí se tím princip zapouzdření.
<viditelnost> <modifikátory> <návratový typ> <název> (typ1 argument1, typ2 argument2, ..., typN argumentN) { // Tělo metody }
Viditelnost
Viditelnost je stejná jako u atributů.
Modifikátory
static
- Metoda sdílená všemi instancemi.final
- Metoda nelze přepsat v dědící třídě.abstract
- Dědící třída tuto metodu musí implementovat.
Návratový typ
Jako návratový typ lze zvolit primitivní datový typ nebo objekt. Pokud nechceme aby metoda vracela hodnotu zle použít jako návratový typ void
.
Název
Název metody začíná malým písmenem a každé další slovo začíná velým písmenem.
Metody s proměnným počtem parametrů
public static int sum(int a, int... b) {
}
// Výše uvedená funkce je kompilátorem převedena na
public static int sum(int a, int[] b) {
}
Objekty
Objekt je instancí třídy. Mějme třídu Student
, která představuje šablonu pro studenta.
public class Student {
// Atributy
private String name;
private int age;
private int clazz;
// Konstruktory
public Student(String name, int age) {
this.name = name;
this.age = age;
clazz = 1;
}
// Metody
void celebrateBirthday() {
age += 1;
}
void passAllExams() {
clazz += 1;
}
//Gettery a Settery
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getClazz() {
return clazz;
}
public void setClazz(int clazz) {
this.clazz = clazz;
}
}
Instancí výše uvedené třídy je například každý student katedry informatiky. Tyto instance nebo-li objekty je liší
hodnotami atributů name
, age
a clazz
. Ovšem chování, které definují metody je stejné.
Práce s objekty
// Vytvoření nového objektu
Student novak = new Student("Jan Novak", 20);
// Volání metod
novak.celebrateBirthday(); // age = 21
novak.getAge() // -> 21
novak.age // Chyba age je deklarovaná jako private.
Dědičnost
Pomocí dědičnosti můžeme omezit redundanci kódu. V Javě lze dědit pouze z jedné třídy. Dědičnost přidáme do definice třídy pomocí extends
.
Pro ilustraci jak funguje dědičnost použijeme třídu Student
a definujeme ji jako potomka třídy Person
.
Ve třídě Person
lze vidět že má shodné atributy name
a age
. Děděním z třídy Person
můžeme vytvořit další třídy jako je například
Teacher
.
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
void celebrateBirthday() {
age += 1;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
// Definice třídy Student jako potomka třídy Person
public class Student extends Person {
private int clazz;
public Student(String name, int age) {
super(name, age)
clazz = 1;
}
void passAllExams() {
clazz += 1;
}
public int getClazz() {
return clazz;
}
public void setClazz(int clazz) {
this.clazz = clazz;
}
}
Rozhraní
Pomocí rozhraní se v Javě řeší vícenásobná dědičnost. Rozhraní se definují stejně jako třídy pouze místo klíčového slova class
je použito interface
. Každá třída může implementovat libovolné množství rozhranní. V Javě 8 lze v rozhraní implementovat metody které jsou
označeny jako static
. Pokud metodu označíme jako default
tak její implementace může ale nemusí být překryta v implementující třídě.
public interface Introduce {
public void introduceMyself();
}
public class Student extends Person implements Introduce {
private int clazz;
public Student(String name, int age) {
super(name, age)
clazz = 1;
}
void passAllExams() {
clazz += 1;
}
public int getClazz() {
return clazz;
}
public void setClazz(int clazz) {
this.clazz = clazz;
}
public void introduceMyself() {
System.out.print("Hello I am student and my name is " + getName());
}
}
// Příklad použití
Introduce selfIntroduceStudent = new Student("Tomas Marny", 20);
selfIntroduceStudent.introduceMyself() // -> Hello I am student and my name is Tomas Marny
// Ověření typu objektu
if (selfIntroduceStudent instanceof Student) {
System.out.print("Student");
}
Úkoly
Implementujte třídu
Point
představující bod v rovině určený dvěma souřadnicemi. V tříde Point implementujte metodudouble distance(Point p)
vracející vzdálenost od daného bodu.-
Implentujte třídu
Line
představující úsečku. Implementujte metody:double getLength()
adouble distance(Point p)
. Vzdálenost bodu od úsečky berte v tomto případě jako nejmenší vzdálenost mezi bodem a všemi body ležícími na úsečce. -
Implementujte třídu
Rectangle
představující obdelník, který má strany vodorovné s osami X a Y. Třída by měla mít dva konstruktory, jeden vytvářející obdelník pomocí dvou bodů, další vytvářející obdelník na základě bodu, výšky a šířky. Implementujte metodudouble getArea()
vracející obsah daného obrazce. Implementujte metodu doubledistance(Point p)
vracející vzdálenost od daného bodu. Vzdálenost bodu od obdelníku berte v tomto případě jako nejmenší vzdálenost mezi bodem a všemi body ležícími na stranách obdelníku. -
Implementujte třídu
Square
představující čtverec. Třída by měla mít konstruktor vytvářející objekt na zákládě souřadnice a délky strany. Implementujte metodudouble getArea()
. Implementujte metodudouble distance(Point p)
vracející vzdálenost od daného bodu. -
Implementujte třídu
Circle
představující kružnici. Třída by měla mít konstruktor vytvářející objekt na zákládě souřadnice a poloměru. Implementujte metodudouble getArea()
. Implementujte metodudouble distance(Point p)
vracející vzdálenost od daného bodu. Vzdálenost bodu od kružnice berte v tomto případě jako nejmenší vzdálenost mezi bodem a všemi body ležícími na kružnici. Vzdálenost nemůže mít zápornou hodnotu! -
Třídy z předchozích příkladů upravte tak, aby se díky dědičnosti omezila redundance kódu. Pokud to má opodstatnění, použijte rozhraní.