JAVA 03 (p) - klasy - obiekty - dziedziczenie

JAVA 03 (p) - klasy - obiekty - dziedziczenie
ukryj menu
SPEC
aktualizacja: 2022-03-18 09:18:43

1. widoczność zmiennych, stałych i funkcji w klasie

zmienne, stałe i funkcje w klasie mogą mieć modyfikatory dostępu

public - zmienna/funkcja widoczna wszędzie bez ograniczeń, tak jest domyślnie
private - zmienna/funkcja widoczna w danej klasie i jej obiektach
protected - zmienna/funkcja widoczna w klasie, jej obiektach i klasach dziedziczących z niej



2. klasa bez konstruktora

class Student{

   // pola (zmienne klasy)
   // metody

}kopiuj


i jej obiekt

Student s = new Student();kopiuj

3. klasa i konstruktor

Konstruktor
– specjalna metoda danej klasy, wywoływana podczas tworzenia jej instancji.
- zadaniem konstruktora jest inicjalizacja obiektu podczas jego tworzenia.
- konstruktor ma taką samą nazwę jak klasa i z punktu widzenia składni jest podobny do metody.
- konstruktory nie mają jednak określonego typu zwracanego.
- zwykle konstruktor nadaje wartości początkowe zmiennym składowym obiektu lub wykonuje inne czynności wymagane do nadania obiektowi ostatecznej postaci.
- niezależnie od tego, czy zdefiniujemy konstruktor, czy nie, wszystkie klasy w języku Java mają konstruktor domyślny
- jeśli zdefiniujemy jednak własny konstruktor, konstruktor domyślny przestanie być używany.

Do tworzenia najłatwiej skorzystać ze skrótu ALT + INSERT w obrębie kodu klasy, i wybrać generate constructor

powstaje konstruktor bez parametrów

class Student {
    public Student() {
    }
}kopiuj


obiekt tej klasy


Student s = new Student();
System.out.println(s.getClass().getName());kopiuj


do konstruktora można przypisać lokalne zmienne

class Student {
    public Student(String name, String lasName, int age) {
    }
}kopiuj


obiekt tej klasy

Student s = new Student("Jan","Kowalski", 15);
System.out.println(s.getClass().getName());kopiuj



w powyższych przypadkach nie ma możliwości dostępu i modyfikacji, zmiennych już po utworzeniu obiektu klasy
innymi słowy name będzie zawsze Jan etc

dlatego możemy utworzyć zmienne w klasie a nie w konstruktorze
jak widać poniżej, maja one modyfikator private, co oznacza że nie ma do nich dostępu spoza tej klasy

class Student {
    
    private String name;
    private String lastName;
    private int age;

}kopiuj


na podstawie tych zmiennych generujemy konstruktor , ALT + INSERT, generate constructor
powstaje taka klasa z konstruktorem

class Student {
    private String name;
    private String lastName;
    private int age;

    public Student(String name, String lastName, int age) {
        this.name = name;
        this.lastName = lastName;
        this.age = age;
    }
}kopiuj



utworzenie obiektu tej klasy działa jak poprzednio, tyle że teraz dane podane w konstruktorze mogą być wykorzystane poza nim
czyli w innych funkcjach


Student s = new Student("Jan","Kowalski", 15);kopiuj

takie zmienne klasy nie powinny być modyfikowane bezpośrednio, dlatego są prywatne
najczęściej chcemy je pobrać (getter) lub zmienić (setter)
podajemy skrót alt + insert / getter


powstały publiczne funkcje umożliwiające pobranie wartości zmiennych w klasie
teraz klasa wygląda tak



class Student {
    private String name;
    private String lastName;
    private int age;    

    public Student(String name, String lastName, int age) {
        this.name = name;
        this.lastName = lastName;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public String getLastName() {
        return lastName;
    }

    public int getAge() {
        return age;
    }
}kopiuj


obiekt tej klasy

Student s = new Student("Jan","Kowalski", 15);kopiuj

pobranie danych obiektu  klasy

System.out.println(s.getName());
System.out.println(s.getLastName());
System.out.println(s.getAge());kopiuj



potem alt + insert / setter

powstały publiczne funkcje umożliwiające zmianę zmiennych w klasie
teraz klasa wygląda tak


class Student {
    private String name;
    private String lastName;
    private int age;


    public Student(String name, String lastName, int age) {
        this.name = name;
        this.lastName = lastName;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public String getLastName() {
        return lastName;
    }

    public int getAge() {
        return age;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
kopiuj

obiekt tej klasy i zmiany (main)

Student s = new Student("Jan","Kowalski", 15);kopiuj

System.out.println(s.getName());
System.out.println(s.getLastName());
System.out.println(s.getAge());

s.setName("Anna");
s.setLastName("Nowak");
s.setAge(12);

System.out.println(s.getName());
System.out.println(s.getLastName());
System.out.println(s.getAge());kopiuj



4. klasa - konstruktory oprócz podstawowego

klasa może posiadać więcej niż jeden konstruktor, czyli innymi słowy, można na różne sposoby zainicjalizować jej obiekt

public Student(String name) {
    this.name = name;
}kopiuj


utworzenie obiektu klasy

Student s = new Student("Piotr");kopiuj

podczas pobrania danych siłą rzeczy zobaczymy, że pozostałe zmienne oprócz name są niezainicjalizowane

System.out.println(s.getName());
System.out.println(s.getLastName());
System.out.println(s.getAge());kopiuj




5. dziedziczenie

Dziedziczenie (ang. inheritance) jest jedną z trzech podstawowych zasad programowania
obiektowego. Jest to mechanizm współdzielenia funkcjonalności pomiędzy klasami, który pozwala na tworzenie hierarchicznej klasyfikacji.
Dziedziczenie umożliwia stworzenie ogólnej klasy, która określa wspólne cechy zbioru powiązanych klas. W języku Java klasa, po której się dziedziczy, nazywa się klasą nadrzędną (ang. superclass), natomiast klasa dziedzicząca jest często nazywana podklasą (ang. subclass).
Podklasa jest specjalną wersją klasy nadrzędnej. Dziedziczy ona wszystkie zmienne oraz metody zdefiniowane w klasie nadrzędnej, dodając swoje własne.

dziedziczenie klasy Student wymaga słowa kluczowego extends


class StudentExtra extends Student {
              
}kopiuj


potem dodajemy tylko jedna zmienną, np salary, oraz konstruktor i getter i setter

class StudentExtra extends Student{

    private int salary;

    public StudentExtra(String name, String lastName, int age, int salary) {
        super(name, lastName, age);
        this.salary = salary;
    }

    public int getSalary() {
        return salary;
    }

    public void setSalary(int salary) {
        this.salary = salary;
    }
}kopiuj




obiekty tej klasy

StudentExtra se1 = new StudentExtra("Jan","Kowalski", 25,1000);

System.out.println(se1.getName());
System.out.println(se1.getLastName());
System.out.println(se1.getAge());
System.out.println(se1.getSalary());

StudentExtra se2 = new StudentExtra("Piotr","Mec", 26,1200);

System.out.println(se2.getName());
System.out.println(se2.getLastName());
System.out.println(se2.getAge());
System.out.println(se2.getSalary());kopiuj



6. nadpisywanie funkcji w klasie - toString()

Wszystkie klasy dziedziczą po klasie Object, która posiada trzy poniższe funkcje

toString(), hashCode(), equals()

można je nadpisać, czyli utworzyć swoje, po to aby

toString() - wypisać jakieś przez siebie założone dane klasy
equals() - utworzyć swój sposób porównania obiektów klasy
hashCode() - utworzyć po swojemu identyfikator obiektu klasy

do nadpisywania służy słowo kluczowe override
w poniższym przykładzie wywołanie toString() zwróci nazwę klasy oraz jej pól

@Override
    public String toString() {
        return this.getClass().getSimpleName() +"{" +
                "name=" + this.name +
                ", lastName=" + this.lastName +
                ", age=" + this.age + "}";
}kopiuj


teraz

Student s = new Student("Jan","Kowalski", 15);
System.out.print(s.toString());kopiuj


daje ładny output w konsoli

Student{name=Jan, lastName=Kowalski, age=15}kopiuj

Uwaga: zobacz jaki output byłby bez nadpisania toString()

co ciekawe funkcja zostaje odziedziczona w klasie StudentExtra

StudentExtra se2 = new StudentExtra("Piotr","Mec", 26,1200);
System.out.println(se2.toString());kopiuj


dając wynik

StudentExtra{name=Piotr, lastName=Mec, age=26}kopiuj

7. nadpisywanie funkcji w klasie - hashCode()

każdy obiekt danej klasy zwraca z użyciem tej funkcji określony numer

Student s = new Student("Jan","Kowalski", 15);
System.out.println(s.hashCode());
Student s2 = new Student("Jan","Kowalski", 15);
System.out.println(s2.hashCode());kopiuj



można go po swojemu nadpisać w funkcji hashCode

@Override
    public int hashCode() {
        return Objects.hash(name, lastName, age);
}kopiuj


albo inaczej

@Override
    public int hashCode() {
        return this.age * this.name.length() * this.lastName.length();
}kopiuj



8. nadpisywanie funkcji w klasie - equals()

obiekty klas porównujemy z użyciem wbudowanej funkcji equals()

Student s = new Student("Jan","Kowalski", 15);
Student s2 = new Student("Jan","Kowalski", 15);
System.out.println(s.getName().equals(s2.getName()));kopiuj


jak widać wartości, czyli Jan się zgadzają - true

inaczej jest w wypadku obiektów

Student s = new Student("Jan","Kowalski", 15);
Student s2 = new Student("Jan","Kowalski", 15);
System.out.println(s.equals(s2));kopiuj


obiekty nie są takie same = false

można po swojemu wygenerować funkcję equals, która w inny sposób sprawdza równość, np na zasadzie porównywania
czy obiekty pochodzą z tej samej klasy, wtedy są równe

@Override
public boolean equals(Object o) {
   return this.getClass() == o.getClass();
}kopiuj




albo jeśli założymy że jeśli obiekty mają te same imiona to są równe

@Override
public boolean equals(Object o) {
   Student student = (Student) o;
   return Objects.equals(this.getName(), student.getName());
}kopiuj



9. dziedziczenie i nadpisywanie funkcji w klasie - inne funkcje

nadpisać można dowolne funkcje publiczne z klas w których dziedziczymy
np w klasie StudentExtra zmieniamy działanie metody getName() z klasy Student


@Override
public String getName() {
   return "Imię studenta: "+super.getName();
}kopiuj



10. zamknięcie funkcji po override w jakiejś klasie, aby inna klasa nie mogła jej nadpisywać

poprzez dodanie modyfikatora final

final @Override
public int hashCode() {
   return this.age * this.age * this.age;
}
kopiuj


11. klasa enum

Enum to typ, który umożliwia w Javie zadeklarowanie ograniczonej liczby możliwych stałych wartości.


enum Letters {
    A,
    B,
    C

}kopiuj


funkcja check() do sprawdzenia tych wartości

static void check(Letters l) {
   switch (l) {
            case A : System.out.println("AAA"); break;
            case B : System.out.println("BBB"); break;
            case C : System.out.println("CCC"); break;
   }

}kopiuj



w main

check(Letters.A);kopiuj


Głównym argumentem na rzecz takiego podejścia jest przejrzystość kodu i brak pomyłek w stringach

Inny typowy przykład wykorzystania klasy enum


enum  Key {
    Right,
    Left,
    Up,
    Down
}kopiuj


funkcja

static void makeMove(Key key) {
        switch (key) {
            case Right : System.out.println("w prawo"); break;
            case Left : System.out.println("w lewo"); break;
            case Up : System.out.println("w górę"); break;
            case Down : System.out.println("w dół"); break;
        }
}kopiuj


wywołanie


makeMove(Key.Right);kopiuj


output z konsoli

ruch w prawokopiuj

12. Listy, sety, mapy, oparte na własnych klasach

definicja klasy Animal

class Animal{
    public Animal(String name, int color) {
    }     
}kopiuj


a) lista zwierząt

ArrayList<Animal> animals = new ArrayList<>();
animals.add(new Animal("kot", 0xFF0000));
animals.add(new Animal("pies", 0xFFFFFF));
System.out.println(animals);kopiuj


lub z inicjalizacją od razu

ArrayList<Animal> animals2 = new ArrayList<>(){
   {
      add(new Animal("kot", 0xFF0000));
      add(new Animal("pies", 0xFFFFFF));
   }
};kopiuj


System.out.println(animals2);


b) mapa zwierząt

Map<String, Animal> animals3 = new HashMap<>();
animals3.put("kot", new Animal("kot syjamski", 0xFF0000));
animals3.put("pies", new Animal("pies husky", 0xFFFF00));

System.out.println(animals3);kopiuj


lub z inicjalizacją od razu

Map<String, Animal> animals4 = new HashMap<>(){
   {
      put("kot", new Animal("kot syjamski", 0xFF0000));
      put("pies", new Animal("pies husky", 0xFFFF00));

   }
};

System.out.println(animals4);kopiuj





13. zadania

Zadanie01. Napisz zgodnie z zasadami programowania obiektowego program, który oblicza pole prostokąta.

Klasa Pole powinna zawierać trzy metody:

- read() - metoda umożliwia wprowadzenie do programu długości boków a i b z klawiatury. W programie należy przyjąć,
że a i b oraz zmienna pole są typu double (rzeczywistego).

- calculate() - metoda oblicza pole prostokąta

- display() - metoda wyświetla długości boków a i b oraz wartość zmiennej pole w określonym formacie. Dla zmiennych
a i b oraz pole należy przyjąć format wyświetlania ich na ekranie z dwoma miejscami po przecinku.

main()


class Zadanie01 {

    public static void main(String[] args) {
        Pole pole = new Pole();
        //
        pole.read();
        pole.calculate();
        pole.display();
    }
}
kopiuj

output z konsoli

ZADANIE 01 - Program oblicza pole prostokąta.
Podaj a.
10
Podaj b.
10
Pole prostokąta o boku a = 10,00 i boku b = 10,00 wynosi 100,00.kopiuj


Zadanie02. Napisz klasę Circle, z trzema konstruktorami

domyślnym, bez parametrów: Circle()
przyjmującym jeden parametr promień: Circle (r)
trzecim, przyjmującym dwa parametry: radius i kolor Circle (r,c)

klasa ma gettery zwracające kolor i promień
klasa ma też funkcję obliczającą powierzchnię okręgu

po utworzeniu w main trzech obiektów tej klasy, otrzymujemy output:

ZADANIE 02 - Circle - konstruktory
Radius = 1.0, area =  3.141592653589793
Radius = 2.0, area = 12.566370614359172, color = red
Radius = 2.0, area = 12.566370614359172, color = bluekopiuj


Zadanie03. Dodaj do powyższej klasy

setter zmianiający kolor i
funkcję obliczającą obwód okręgu
nadpisz funkcję toString() zwracającą dane o obiekcie klasy

po serii wywołań w main() mamy output jak poniżej

ZADANIE 03 - Circle2 - setters
Circle2{radius=10.0, color='red'}
area = 314.1592653589793
circumstance = 62.83185307179586
Circle2{radius=10.0, color='blue'}
Circle2{radius=20.0, color='blue'}
area = 1256.6370614359173
circumstance = 125.66370614359172kopiuj


Zadanie04. Napisz program, który rekurencyjnie oblicza kolejne wartości n!
dla n wprowadzonego z konsoli i wynik wyświetla na ekranie komputera.

Klasa Silnia powinna zawierać funkcję liczSilnie()

Metoda main()
- utworzenie obiektu klasy Silnia
- pobranie inputa z klawiatury
- obliczenie silni z wywołaniem metody liczSilnie()

output z konsoli jak poniżej:


Obliczanie silni dla dowolnej liczby całkowitej.
Podaj n.
4
1! = 1
2! = 2
3! = 6
4! = 24kopiuj



większe przykłady

Obliczanie silni dla dowolnej liczby całkowitej.
Podaj n.
50
...
50! = 30414093201713378043612608166064768844377641568960512000000000000kopiuj


Obliczanie silni dla dowolnej liczby całkowitej.
Podaj n.
80
...
80! = 71569457046263802294811533723186532165584657342365752577109445058227039255480148842668944867280814080000000000000000000kopiuj



Uwaga: do obliczenia większych wartości nie wystarczy typ int czy nawet long
Java dostarcza tutaj specjalny typ BigInteger:

https://docs.oracle.com/javase/7/docs/api/java/math/BigInteger.html
https://nullbeans.com/what-is-a-biginteger-and-how-to-use-it-in-java/

Sprawdzenie wyniku
https://pl.numberempire.com/factorialcalculator.php

Zadanie05. Napisz program, w którym zdefiniowano klasę dla danych Osoba

zawierającą następujące pola nazwisko, miasto, kod oraz metody: init(), display(), checkCode()

init() umożliwia wprowadzenie danych,
display() wyświetla je na ekranie komputera
check() sprawdza poprawność kodu pocztowego, bez gotowych rozwiązań w postaci wyrażeń regularnych

wywołanie powinno wyglądać tak:

class Zadanie05 {
    public static void main(String[] args) {
        Osoba o = new Osoba();
        o.init();
    }
}kopiuj


output z konsoli


Wprowadzanie danych
Podaj nazwisko:
a
Podaj miasto:
a
Podaj kod pocztowy:
a
podaj dokładnie sześć cyfr kodu i kreskę na trzecim miejscu
aa-a
podaj dokładnie sześć cyfr kodu i kreskę na trzecim miejscu
aa-aaa
podaj dokładnie sześć cyfr kodu i kreskę na trzecim miejscu
11-1
podaj dokładnie sześć cyfr kodu i kreskę na trzecim miejscu
11-111
=======================
Wyświetlenie danych
Nazwisko: a
Miasto: a
Kod: 11-111
kopiuj


Zadanie06. Zarządzaj ustawieniami fabrycznymi robota

Kiedy roboty schodzą z fabryki, nie mają nazwy.
Przy pierwszym uruchomieniu (czyli utworzeniu obiektu klasy Robot), generowana jest losowa nazwa w formacie dwóch wielkich liter (funkcja generateName()) po których następują trzy cyfry, na przykład RX-837 lub BC-811.

Co jakiś czas musimy zresetować robota co oznacza, że jego nazwa zostanie wyczyszczona. (funkcja reset())
Następnym razem, gdy zapytasz o nazwę, funkcja odpowie nową losową nazwą.

Nazwy muszą być losowe: nie powinny mieć przewidywalnej kolejności.
Losowe nazwy oznaczają ryzyko kolizji. Twoje rozwiązanie musi zapewniać, że każdy istniejący robot ma unikalną nazwę (while)

Konstrukcja programu:

klasa Robot, a w niej funkcje reset(), generateName(), makeRandom()

wywołanie dokładnie jak poniżej

class Zadanie06 {
    public static void main(String[] args) {
        Robot robot = new Robot();
        System.out.println(robot.getName());
        for (int i = 0; i <10 ; i++) {
            robot.reset();
            System.out.println(robot.getName());
        }
    }
kopiuj
}kopiuj



przykładowy output z konsoli

LQ-456
IF-659
JE-458
ET-794
ZZ-950
OX-626
GX-014
LR-291
HV-533
DB-657
LF-486kopiuj


sugestia

do przechowywania wykorzystanych wcześniej nazw robota użyj mapy

Zadanie07. Zaimplementuj zegar obsługujący godziny w formacie hh:mm

Zegar umożliwia dodawanie i odejmowanie minut.

Dwa zegary, które reprezentują ten sam czas, powinny być sobie równe (equals)
Potrzeba nadpisać metodę toString()
Potrzeba nadpisać metodę equals()

output z konsoli

=========== ZEGARY
wywołanie c1.toString()
jest godzina 10:10
wywołanie c1.hashCode()
320
wywołanie c1.equals(c2)
true
podaj liczbę minut do dodania:
90
wywołanie c1.toString()
jest godzina 11:40
podaj liczbę minut do odjęcia:
odjęcie 50 minut
50
wywołanie c1.toString()
jest godzina 10:50
kopiuj


Zadanie08. Faktury

Utwórz dwie klasy: Invoice i Invoices

Klasa Invoice
- przyjmuje parametry: id, description, quantity i unitPrice
- posiada odpowiednie settery, gettery i  metodę toString()

Klasa Invoices
- przyjmuje listę obiektów klasy Invoice
- posiada metodę liczącą sumę quantities we wszystkich fakturach
- posiada metodę liczącą średnią cenę jednostkową

main()

tworzy listę pięciu faktur z poniższymi danymi
"A001", "faktura 001", 1, 1.50
"A002", "faktura 002", 2, 2.50
...
...
"A005, "faktura 005", 5, 5.50

i wywołuje

System.out.println(invoices.toString());kopiuj

output z konsoli

ZADANIE 08 - faktury
17.5
Invoices{allQuantities=15, getAverageUnitPrice=1.1666666666666667}kopiuj

Zadanie09. Punkty

Utwórz klasę MyPoint a w niej:
- konstruktor domyślny bez parametrów
- konstruktor przyjmujący dwa argumenty x,y
- funkcję zwracającą punkt w postaci tablicy [x,y]
- funkcję liczącą odległość od punktu 0,0
- funkcję liczącą odległość od podanych współrzędnych x,y
- funkcję liczącą odległość od innego punktu klasy MyPoint
- funkcję toString()


seria wywołań z konsoli

ZADANIE 09 - Punkty
MyPoint{x=0, y=0}
punkt p1 ma współrzędne = [0, 0]
dodaję punkt p2
MyPoint{x=3, y=4}
odległość p2 od p1 od punktu 0,0 = 5.0
dodaję punkt p3
MyPoint{x=5, y=6}
odległość p3 od p2 = 2.8284271247461903
dodaję punkt p4
MyPoint{x=10, y=10}
odległość p4 od podanych x=11,y=11 = 1.4142135623730951kopiuj

Zadanie10. Napisz klasę Triangle

zawierającą metody, które

- rysują trójkąt w konsoli
- sprawdzają czy zadany z konsoli punkt znajduje się w obrębie trójkąta którego wierzchołki to współrzędne
 [0,0],[10,0], [0,10]

output z konsoli

ZADANIE 10 - trójkąt
mamy trójkąt o współrzędnych [0,0],[10,0], [0,10]
.    .    .    .    .    .    .    .    .    .   
.                                .
.                            .
.                        .
.                    .
.                .
.            .
.        .
.    .
.

podaj x szukanego punktu:
4
podaj y szukanego punktu:
5
.   .    .    .    .    .    .    .    .    .    .   
.                                    .
.                                .
.                            .
.                        .
.                x    .
.                .
.            .
.        .
.   .
.

Punkt o współrzędnych x=4, y=5 jest w trójkącie!kopiuj


Zadanie11.

Wykonaj powyższe zadanie dla dowolnego trójkąta o dodatnich współrzędnych.
Można tez przesunąć układ współrzędnych na inne miejsce niż początek okna konsoli
aby umożliwić tworzenie trójkąta o ujemnych współrzędnych
Wizualizacja powinna pokazywać trzy wierzchołki trójkąta oraz szukany punkt
Wszystkie dane wprowadzamy z klawiatury
Program powinien zawierać klasy MyTriangle i MyPoint


Zadanie12. Utwórz klasę MyCircle

której konstruktor przyjmuje: współrzędne środka (x,y) i promień okręgu (r)

klasa posiada metody do:
- obliczenia odległości okręgu (nie jego środka) od zadanych współrzędnych (x,y)
- obliczenia odległości okręgu (nie jego środka) od zadanego punktu klasy MyPoint
- obliczenia odległości (nie środka) okręgu od zadanego okręgu klasy MyCircle

klasa zwraca odpowiednie informacje w wypadku jeśli
- punkt zawiera się w okręgu
- drugi okrąg ma część wspólną z pierwszym