Java – podstawy
Klasa
Podstawowy element programowania obiektowego, który stanowi szablon do tworzenia obiektów. Definiuje ona właściwości (pola) oraz zachowania (metody) obiektów, które na jej podstawie zostaną utworzone.
Składnikami klasy są:
Specyficzną klasą wbudowaną w język Java jest klasa String, która służy do reprezentacji sekwencji znaków (czyli ciągu tekstowego). Jest to jedna z najczęściej używanych klas w języku Java.
Kluczowe cechy klasy String:
String s1 = "Hello";
String s2 = "Hello";
W rzeczywistości to będzie ten sam obiekt w pamięci.
Metody klasy String:
Package
Mechanizm służący do katalogowania projektu. Tworzenie powiązanych ze sobą klas, interfejsów i innych elementów co pozwala na lepszą organizację kodu oraz zapobieganie konfliktom nazw.
Przykład:
com.nazwa_domeny.nazwa_aplikacji.przykład_pierwszy
com.nazwa_domeny.nazwa_aplikacji.przykład_drugi
Jeżeli piszemy klasy, które znajdują się w różnych package’ach musimy zaimportować daną klasę, którą chcemy zadeklarować w innej klasie. Jeżeli klasy znajdują się w tym samym package’u to nie ma konieczności importowania ich jeżeli chcemy utworzyć obiekt jednej klasy w drugim.
Modyfikatory dostępu
Słowa kluczowe, które przypisujemy polom, które określają dostępność do danego pola.
public int polePubliczne; //dostępny wszędzie
protected int poleDziedziczenie //dostępny w dziedziczeniu oraz w tym samy package'u
private int polePrywatne //dostępny w obrębie klasy, w której istnieje
int poleBezNiczego //package - dostępny w tym samym package'u
Static
Są to pola współdzielone przez wszystkie obiekty danej klasy. Oznacza to, ze istnieje tylko jedna kopia takiej zmiennej, niezależnie od tego ile obiektów takiej klasy zostanie utworzonych.
Do takiej zmiennej statycznej można uzyskać dostęp bez tworzenia obiektu klasy, po prostu odwołując się do niej przez nazwę klasy. Analogicznie działają metody statyczne.
NazwaKlasy.poleStatic = 15;
obiekt.poleStatic = 123;
Final
Słowo, które służy do definiowania elementów, których wartość lub definicja nie może zostać zmieniona po ich nadaniu. Może być stosowana do zmiennych, metod oraz klas. W każdym z tych kontekstów ma nieco inne znaczenie.
- final dla zmiennych – zmienna nie może zostać zmieniona po przypisaniu jej wartości.
- final dla metod – metoda nie może być modyfikowana przez podklasy. Jest używanan w sytuacjach, gdzie chcesz uniemożliwić modyfikację zachowania metody w klasach dziedziczących.final dla klas – klasa nie może być dziedziczona przez inne klasy.
Dziedziczenie klasy
mechanizm programowania obiektowego, który umożliwia jednej klasie przejęcie właściwości i metod innej klasy. Klasa, która dziedziczy nazywana jest klasą pochodną lub podklasą. Klasa, której dziedziczy to klasa bazowa lub nadklasa.
Kluczowe cechy dziedziczenia
- Podklasa dziedziczy właściwości i metody nadklasy. Wszystkie pola i metody klasy bazowej są dostępne w klasie pochodnej (chyba, że są oznaczone jako prywatne).
- Podklasa może dodawać nowe metody i pola
- Podklasa może nadpisywać metody klasy. Mechanizm ten nazywa się nadpisywaniem metod.
Zasady dziedziczenia
- Prywatne elementy nie są dziedziczone
- Konstruktory nie są dziedziczone.
- Podklasa może nadpisywać metody, chyba, że jest ona oznaczona jako final.
- Polimorfizm
Super
Słowo kluczowe, które pozwala na dostęp do elementów metod i pół nadklasy, które zostały nadpisane. Może być używane zarówno w konstruktorach, jak i metodach.
Rzutowanie obiektów
Zmiana typu referencji obiektu, który istnieje w pamięci na inny typ. Umożliwia to używanie obiektu w kontekście innego typu klasy, co jest często potrzebne, gdy korzystamy z mechanizmów dziedziczenia lub polimorfizmu.
Klasa wewnętrzna
Klasa zdefiniowana w obrębie innej klasy.
Klasa anonimowa
Specjalny rodzaj klasy wewnętrznej, która nie ma swojej nazwy i jest tworzona w locie. Jest używana głównie wtedy, gdy potrzebujemy jednorazowej implementacji interfejsu lub nadpisania metod klasy, bez konieczności tworzenia pełnej, nazwanej klasy. Klasy anonimowe wykorzystujemy kiedy wiemy, że w jakimś wyjątkowym przypadku będziemy chcieli nadpisać lub zaimplementować jakąś metodę.
Klasa abstrakcyjna
Klasa, której nie można bezpośrednio zainicjalizować, czyli nie można bezpośrednio utworzyć jej obiektu. Służy ona jako szablon dla innych klas i zazwyczaj zawiera metody abstrakcyjne, które muszą zostać zaimplementowane przez klasy dziedziczące. Może również zawierać normalne metody z pełnymi implementacjami.
Klasy abstrakcyjne są używane wtedy, gdy chcemy zdefiniować wspólne zachowania i właściwości dla grupy klas, ale nie chcemy, aby klasa była bezpośrednio instancjonowana.
// Definicja klasy abstrakcyjnej
abstract class Shape {
// Abstrakcyjna metoda do obliczania pola
abstract double area();
// Metoda do wyświetlania typu kształtu
void display() {
System.out.println("This is a shape.");
}
}
// Klasa Circle dziedzicząca po klasie Shape
class Circle extends Shape {
private double radius;
// Konstruktor klasy Circle
public Circle(double radius) {
this.radius = radius;
}
// Implementacja metody area() dla okręgu
@Override
double area() {
return Math.PI * radius * radius; // Pole okręgu = πr²
}
}
Cechy klasy abstrakcyjnej
- Klasa abstrakcyjna może zawierać zarówno abstrakcyjne, jak i nieabstrakcyjne (zwykłe) metody.
- Klasa abstrakcyjna nie może być instancjonowana bezpośrednio, czyli nie można utworzyć jej obiektu.
- Aby używać klasy abstrakcyjnej, trzeba ją rozszerzyć (extends), a następnie zaimplementować wszystkie jej abstrakcyjne metody w klasie pochodnej.
- Abstrakcyjna metoda to metoda zadeklarowana w klasie abstrakcyjnej bez jej implementacji. Klasy dziedziczące muszą nadpisać i zdefiniować metody.
Interfejs
Specjalny typ klasy, który definiuje zbiór metod, ale nie zawiera ich implementacji (przed Java 8). Jest to mechanizm, który pozwala na tworzenie kotraktów – klasa, która implementuje dany interfejs, musi dostarczyć iimplementacje wszystkich metod zdefiniowanych w tym interfejsie.
Interfejsy są głównie używane do definiowania zachowań, które mogą być współdzielone przez różne klasy, niezależnie od pochodzenia w hierarchii klas. Dzięki interfejsom Java wspiera wielodziedziczenie zachowań, co oznacza, że klasa moze implementować wiele interfejsów jednocześnie.
// Definicja interfejsu
interface Animal {
// Metody interfejsu (domyślnie są one publiczne i abstrakcyjne)
void makeSound(); // Metoda do wydawania dźwięku przez zwierzę
void eat(); // Metoda do jedzenia przez zwierzę
}
// Klasa Dog implementująca interfejs Animal
class Dog implements Animal {
// Implementacja metody makeSound
public void makeSound() {
System.out.println("Bark");
}
// Implementacja metody eat
public void eat() {
System.out.println("Dog is eating.");
}
}
Klasa Thread
Jest to wbudowana klasa, która umożliwia tworzenie i zarządzanie wątkami w programie. Wątek to niezależna ścieżka wykonywania, co oznacza, że można wykonywać jednocześnie wiele zadań w ramach jednej aplikacji. Wątki są podstawą programowania wielowątkowego, które pozwala na wykonywanie wielu operacji jednocześnie.
// Dziedziczenie po klasie Thread
class MyThread extends Thread {
// Metoda run() zawiera kod, który będzie wykonany przez wątek
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.println(Thread.currentThread().getName() + " - Licznik: " + i);
try {
Thread.sleep(1000); // Uśpienie wątku na 1000 ms (1 sekunda)
} catch (InterruptedException e) {
System.out.println(e);
}
}
}
}
public class Main {
public static void main(String[] args) {
// Tworzenie instancji klasy MyThread
MyThread thread1 = new MyThread();
MyThread thread2 = new MyThread();
// Uruchamianie wątków
thread1.start(); // Uruchamia nowy wątek
thread2.start(); // Uruchamia nowy wątek
}
}
join()
Metoda, która używana jest w kontekście programowania wielowątkowego i służy do synchronizacji wątków. Jej głównym celem jest umożlwienie jednemu wątkowi czekania na zakończenie innego wątku, zanim kontynuuje swoje działanie. Jest to przydatne w sytuacjach, gdy proces wykonywania programu zależy od wyniku działania innego wątku lub chcemy zapewnić, że pewne operacje będą wykonane w odpowiedniej kolejności.
isAlive()
Metoda używana do sprawdzania, czy dany wątek jest aktualnie aktywny. Metoda zwraca wartość typu boolean.
interrupt()
Jest używana do przerywania wątku. Gdy wątek wywołuje interrupt() na innym wątku, oznacza to, że chce sygnalizować temu wątkowi, aby zaprzestał atualnej pracy, jeśli to możliwe. Wątki mają wbudowany mechanizm obsługi przerwań, który umożliwia reagowanie na takie sygnały.
Klasa scanner
Jest to wbudowana klasa, która służy do odczytywania danych wejściowych z różnych źródeł, takich jak klawiatura, pliki, ciągi tekstowe itp. Umożliwia łatwe przetwarzanie przetwarzanie danych wejściowych, w tym analizowanie tekstu, rozdzielanie do na tokeny oraz konwertowanie na różne typy danych (np. int, double, String)
Metody klasy scanner
Metody do odczytywania różnych typów danych:
Metody sprawdzające dostępność danych wejściowych:
Metody zarządzające strumieniami danych:
Paradygmaty programowania obiektowego
Enumy
To specjalny typ danych, który pozwala definiować zestaw stałych wartości. Enumy są szczególnie przydatne, gdy masz do czynienia z ograniczonym zbiorem możliwości, które są wzajemnie wykluczające się, np. dni tygodnia, pory roku, kierunki geograficzne itp.
Cechy enumów:
public enum Day {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
public class Main {
public static void main(String[] args) {
Day today = Day.MONDAY;
if (today == Day.MONDAY) {
System.out.println("It's Monday!");
}
}
}