Obiektowość

Omówię tutaj styl programowania w Javie, czyli obiektowość.
Programowanie w tym języku jest programowaniem obiektowym (Object Oriented Programming – OOP).
W programowaniu tym skupiamy się głównie na danych – obiektach, a dopiero potem na algorytmach/metodach, które je przetwarzają.
Klasa jest określeniem sposobu tworzenia obiektów. Tworząc nowy obiekt tworzymy nową instancję danej klasy.
Z obiektowością związane jest pojęcie hermetyzacji, czyli zamknięcie danych przed dostępem z zewnątrz. Dane zawarte w obiekcie nazywane są danymi składowymi, a funkcje operujące na tych danych metodami. Określają one łącznie stan obiektu.
Obiekt posiada trzy podstawowe cechy:
1. Zachowanie – czyli co można zrobić z obiektem i jakie metody zawiera
2. Stan – reakcja obiektu na wywołane na nim metody
3. Tożsamość – cechy, które odróżniają obiekt od innych o tym samym zachowaniu i stanie
Relacje między klasami:
zależność (jedna klasa używa innej, która nie jest z nią zbytnio powiązana)
agregacja (zawieranie)
dziedziczenie (że klasa jest jakby daną klasą – rozszerza ją)
Możemy używać już klas predefiniowanych z biblioteki Javy.
Nowe obiekty tworzymy za pomocą słowa kluczowego „new” i tworzone są one przy pomocy konstruktorów.
Przykładowy listing kodu:

package net.javainfo.objectivity;

import java.time.DayOfWeek;
import java.time.LocalDate;

public class Calendar {

    public static void main(String[] args){

        LocalDate date = LocalDate.now();
        int month = date.getMonthValue();
        int today = date.getDayOfMonth();

        date = date.minusDays(today - 1);
        DayOfWeek weekday = date.getDayOfWeek();
        int value = weekday.getValue();


        System.out.println(" Pn  Wt  Sr  Cz  Pt  Sb  Nd");
        for(int i = 1; i < value; ++i)
            System.out.print("    ");
        while(date.getMonthValue() == month){
            System.out.printf("%3d",date.getDayOfMonth());
            if(date.getDayOfMonth() == today)
                System.out.print("*");
            else
                System.out.print(" ");
            date = date.plusDays(1);
            if(date.getDayOfWeek().getValue() == 1)
                System.out.println();
        }
        if(date.getDayOfWeek().getValue() != 1)
            System.out.println();

    }
}

Jak definiujemy własne klasy?
Otóż przyjmujemy regułę, że klasa zawiera własne pola i metody. Oraz konstruktory, wykorzystywane przy tworzeniu instancji obiektów.
W jednym pliku może być wiele klas, jedna tylko może być publiczna i mieć nazwę pliku.
Ogólne zasady tworzenia konstruktorów:
-musi mieć taką samą nazwę jak klasa
-klasa może mieć więcej niż jeden konstruktor
-konstruktor może przyjmować zero lub więcej parametrów
-nie zwracają one wartości jak metody
-wywoływany zawsze przy użyciu słowa kluczowego „new”
Od Javy 10 zmienne lokalne można deklarować przy pomocy słowa kluczowego „var„:

//zamiast:
Object obiekt = new Object();
//można napisać:
var obiekt = new Object();

Brak obiektu oznaczany jest przez specjalną wartość „null”. Często będzie się można spotkać z wyjątkiem „NullPointerException„, czyli odwołaniem się do wartości null.
Możemy spotkać się z parametrami jawnymi i niejawnymi.
Niejawne to te w metodzie korzystające z pól klasy, a jawne to te podane w definicji metody w nawiasach: „()”.
Hermetyzacja opiera się głównie na tym, że pola składowe z reguły tworzymy prywatne, metody dostępu i mutatory(zmieniające te pola) publiczne.
Stałe tworzymy przy użyciu słowa kluczowego „final„.
Pola i metody statyczne, to takie, przy których nie musimy tworzyć nowych obiektów.
Są one inicjalizowane raz przy kompilacji programu.
Przykład zastosowania:

package net.javainfo.objectivity;

//Przykład zastosowania pola i metody statycznej
public class StaticExample {

    public static void main(String[] args){

        var customers = new Customer[3];
        customers[0] = new Customer("Jan Kowalski", 2300);
        customers[1] = new Customer("Piotr Nowakowski", 400);
        customers[2] = new Customer("Anna Nowicka", 1540);

        for(Customer c : customers){
            System.out.println(c.toString());
        }
    }
}

class Customer{

    private static int nextId = 1; //raz zainicjalizowane pole składowe jako statyczne
    private String name;
    private double amount;
    private int id;

    Customer(String name, double amount){
        this.name = name;
        this.amount = amount;
        id = setId();
    }

    public static int setId(){ //demonstracja działania metody statycznej
        int tmp = nextId;
        nextId++;
        return tmp;
    }

    public int getId(){
        return this.id;
    }

    public String getName(){
        return this.name;
    }

    public double getAmount(){
        return this.amount;
    }

    @Override
    public String toString() {
        return "Customer{" +
                "name='" + name + '\'' +
                ", amount=" + amount +
                ", id=" + id +
                '}';
    }
}

Parametry są przekazywane do metod przez wartość.
Zasady dotyczące używania parametrów metod:
-metoda nie może modyfikować parametru typu podstawowego
-metoda może zmienić stan obiektu przekazanego jako parametr
-metoda, nie może sprawić, aby parametr zaczął się odwoływać do nowego obiektu
Przykład:

package net.javainfo.objectivity;

//Przykład sposobów przekazywania parametrów do metod
public class Parameter {

    public static void main(String[] args){

        double x = 200;

        //metoda nie może zmodyfikować parametru typu podstawowego
        System.out.println("Wartość x przed metodą: " + x);
        raiseValue(x);
        System.out.println("Wartość x po metodzie: " + x);

        //metoda może zmienić stan obiektu przekazanego jako parametr
        Customer2 customer = new Customer2("Asia", 200);
        System.out.println("Customer przed zmianą: " + customer);
        raiseObjectValue(customer);
        System.out.println("Customer po zmianie " + customer);

        //metoda nie może sprawić, aby parametr obiektowy zaczął się odwoływać do nowego obiektu
        Customer2 customer2 = new Customer2("Carol", 300);
        System.out.println("Przed zamianą: " + "Customer1: " + customer + "\nCustomer2: " + customer2);
        swapObject(customer,customer2);
        System.out.println("Po zamianie :" + "Customer1: " + customer + "\nCustomer2: " + customer2);

    }

    public static void raiseValue(double value){
        value *= 2;
    }

    public static void raiseObjectValue(Customer2 customer){
        customer.setAmount(customer.getAmount()*2);
    }

    public static void swapObject(Customer2 customer1, Customer2 customer2){
        Customer2 temp = customer1;
        customer1 = customer2;
        customer2 = temp;
    }
}

class Customer2{

    private String name;
    private double amount;

    Customer2(String name, double amount){
        this.name = name;
        this.amount = amount;
    }

    public String getName() {
        return name;
    }

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

    public double getAmount() {
        return amount;
    }

    public void setAmount(double amount) {
        this.amount = amount;
    }

    public void raiseAmount(){
        this.amount *= 2;
    }

    @Override
    public String toString() {
        return "Customer{" +
                "name='" + name + '\'' +
                ", amount=" + amount +
                '}';
    }
}

Nowe obiekty tworzymy poprzez słowo kluczowe „new„. Możemy je tworzyć na wiele sposobów, dzięki przeciążaniu, czyli utworzeniu kilku metod/konstruktorów o tej samej nazwie. Domyślnie pola składowe klasy są inicjalizowane w sposób domyślny, pola typów liczbowych na 0, boolean na false, a referencje obiektów na null.
Konstruktorem domyślnym jest konstruktor bezargumentowy. Jest on domyślnie wywoływany, nawet jak go nie ma w kodzie. Natomiast jeżeli przeciążymy go innym, musimy ręcznie go wprowadzić.
Przyjmuje się, że w konstruktorze odnosimy się do zmiennej składowej poprzez słowo kluczowe „this”:

public Note(int id, String content){
     this.id = id;
     this.content = content;
}

Przez this w jednym konstruktorze możemy też wywołać inny,np.:

public Note(String content){
     this();
}

Pamiętajmy, że wtedy konstruktor musi być pierwszą instrukcją w bloku.
Poprzez blok inicjujący można również zainicjalizować pola egzemplarza:

class Note{
     private static int nextId;
     int id;
     String content;
     {
           id = nextId;
           nextId++;
     }

Są one wykonywane przy każdym konstruowaniu nowego obiektu.

Istnieje jeszcze w Javie coś takiego jak rekordy.
Jest to specjalny rodzaj klasy o niezmiennym stanie, którego zawartość jest ogólnie dostępna.

record Point(double x, double y){}

W ten sposób mamy klasę zawierającą:

private final double x;
private final double y;
//konstruktor:
Point(double x, double y);
//metody dostępowe:
public double x();
public double y();

Możemy dodawać do rekordu własne metody, oraz pola statyczne/metody.
Nie można natomiast tworzyć samemu pól egzemplarza.

Domyślny konstruktor zwany jest konstruktorem kanonicznym. Konstruktor niestandardowy może być tworzony przez programistę dodatkowo, ale w pierwszej instrukcji bloku musi wywołać inny konstruktor.
Możemy korzystać w konstruktorze kanonicznym formę kompaktową, w której nie podajemy listy parametrów:

record Point(double x, double y){
     public Point{
           double tmp = x;
           x = y;
           y = tmp;
       }
}

Pakiety tworzymy poprzez użycie nazwy odwróconej domeny, tak jak w internecie adres strony. Żeby nie było konfliktu nazw.
Np. net.javainfo
Potem stosujemy nazwę projektu czy inną dowolną.
Klasy zewnętrzne importujemy po słowie kluczowym „package„, które musi być wywołane pierwsze w kodzie, dopiero potem stosujemy importy poprzez słowo „import” i pełna nazwa pakietu, np. java.util.*;
„*” oznacza że importujemy wszystkie klasy z pakietu java.util.

JDK zawiera javadoc, czyli narzędzie do tworzenia komentarzy dokumentacyjnych.
Tworzymy je poprzez /** */.
Niektóre ze znaczników to:
@author
@version
Generujemy je poprzez komendę:

javadoc -d docDirectory nazwaPakietu

Wywołujemy ją w katalogu z plikami źródłowymi.


Opublikowano

w

przez

Komentarze

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *