Wykład 3
w Javie argumenty są zawsze przekazywane przez wartość.
Sama deklaracja daje “niezainicjowaną tablicę”
Tablica pusta w Javie to tablica, która ma rozmiar zero. Innymi słowy, nie może przechowywać żadnych elementów, ale to wciąż jest prawidłowy obiekt tablicy.
Jeśli tablica jest równa null, oznacza to, że nie odnosi się do żadnego obiektu w pamięci. Jest to specjalna wartość, która reprezentuje, że zmienna tablicy nie ma aktualnie przypisanego obiektu.
ArrayListArrayList to jedna z najczęściej używanych implementacji interfejsu List. Jest to dynamicznie rozszerzalna tablica, która może zmieniać swój rozmiar w miarę dodawania i usuwania elementów. Wewnętrznie ArrayList używa tablicy do przechowywania elementów.
Własności:
Wewnętrzna struktura danych: Jak wspomniano wcześniej, ArrayList wewnętrznie używa tablicy do przechowywania elementów. Gdy lista staje się pełna i potrzeba dodać kolejny element, Java tworzy większą tablicę i kopiuje elementy starej tablicy do nowej.
Rozmiar vs. Pojemność:
ArrayList może zmieniać swój rozmiar w miarę potrzeb, co czyni ją bardziej elastyczną niż zwykłe tablice.null.LinkedList z powodu dodatkowej pojemności rezerwowej.Bezpieczeństwo wątkowe: Standardowa implementacja ArrayList nie jest synchronizowana, co oznacza, że nie jest bezpieczna do użytku w środowiskach wielowątkowych bez odpowiedniej synchronizacji. Jeśli potrzebujesz wersji synchronizowanej, możesz użyć Collections.synchronizedList().
Pamięć: Jeśli znasz ostateczny rozmiar listy, warto zainicjalizować ArrayList z odpowiednią pojemnością początkową, aby uniknąć wielokrotnego rozszerzania wewnętrznej tablicy.
Okej, przyjrzyjmy się niektórym z najczęściej używanych metod i właściwości klasy ArrayList w Javie:
add(E element):
add(int index, E element):
get(int index):
remove(int index):
remove(Object o):
size():
isEmpty():
clear():
contains(Object o):
indexOf(Object o):
set(int index, E element):
toArray():
Klasy takie jak ArrayList są generycznymi klasami kontenerowymi, które przechowują obiekty, a nie typy proste. Dlatego nie możemy bezpośrednio użyć int lub double jako typu elementu dla ArrayList.
Aby rozwiązać ten problem, Java dostarcza klasy opakowujące (wrapper classes) dla wszystkich typów prostych. Dla int mamy Integer, dla double mamy Double itd.
Dzięki autoboxingowi (automatyczne konwersje między typami prostymi a ich klasami opakowującymi) korzystanie z tych klas opakowujących jest stosunkowo proste i wygodne.
Dla int:
Dla double:
Domyślne wyświetlanie zawartości ArrayList jest dość proste dzięki nadpisanemu przez klasę ArrayList metodzie toString(). Gdy wywołasz metodę System.out.println na obiekcie ArrayList, Java automatycznie wywołuje metodę toString() klasy ArrayList.
Niezainicjowana lista tablicowa:
ArrayList, ale nie przypisującej jej do żadnego obiektu.Pusta lista tablicowa:
ArrayList został zainicjowany, ale nie zawiera żadnych elementów.ArrayList i możesz wykonywać na nim operacje, takie jak dodawanie i usuwanie elementów.null:
ArrayList jest jawnie ustawiona na wartość null lub domyślnie jest ustawiona na null i nie została zainicjowana później.null, spowoduje błąd w czasie wykonywania zwanym NullPointerException.import java.util.ArrayList;
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
ArrayList<String> lt1 = new ArrayList<>();
ArrayList<String> lt2 = new ArrayList<>(10); // Pojemność początkowa 10
ArrayList<Integer> lt3 = new ArrayList<>(){{
add(5);
add(-4);
add(3);
}};
}
} Inicjalizacja:
Używanie metody System.identityHashCode nie jest zalecane!
Niezmienność (Immutability):
String są niezmienne. Oznacza to, że raz utworzony łańcuch znaków nie może być zmieniony. Wszelkie operacje modyfikujące zawartość łańcucha (np. dodawanie, usuwanie znaków) skutkują stworzeniem nowego obiektu String.Konkatenacja:
+:Porównywanie:
equals() zamiast operatora ==:Pamięć:
new.Zmienne łańcuchowe:
StringBuilder i StringBuffer. Są one szczególnie przydatne w sytuacjach, gdzie zachodzi wiele modyfikacji łańcucha, ponieważ operują one w miejscu (in-place) i są zwykle szybsze niż tworzenie wielu obiektów String.nullWartość:
""): To faktyczny obiekt klasy String, który ma wartość, ale ta wartość jest pusta. Inaczej mówiąc, jest to łańcuch, który nie zawiera żadnych znaków.null: To specjalna wartość, która oznacza, że zmienna nie wskazuje na żaden obiekt. Dla zmiennej typu String, jeśli jest ona ustawiona na null, nie wskazuje ona na żaden łańcuch (pusty czy inny).Długość:
""): Jego długość wynosi 0. Można to sprawdzić używając metody length(): "".length() zwróci 0.null: Zmienna o wartości null nie posiada metod ani atrybutów. Próba wywołania metody, np. null.length(), spowoduje wyjątek NullPointerException.Operacje:
""): Możesz wykonywać na nim różne operacje, takie jak konkatenacja czy wywoływanie innych metod klasy String.null: Nie możesz wykonywać na nim żadnych operacji. Każda próba dostępu do metody lub atrybutu na zmiennej o wartości null spowoduje NullPointerException.Porównywanie:
Możesz porównać zarówno łańcuch pusty, jak i null z innymi łańcuchami. Ale musisz być ostrożny z null, ponieważ:
Zastosowania:
""): Często używany do inicjowania łańcuchów bez konkretnej wartości lub do wskazania, że łańcuch powinien być “czysty” lub “bez wartości”, ale nadal istnieje.null: Wskazuje, że zmienna nie odnosi się do żadnego obiektu. Jest używane w wielu przypadkach, np. gdy wartość nie jest jeszcze znana lub nie została ustawiona.length():
Zwraca liczbę znaków w łańcuchu.
charAt(int index):
Zwraca znak na określonej pozycji w łańcuchu.
substring(int beginIndex, int endIndex):
Zwraca nowy łańcuch zawierający znaki z oryginalnego łańcucha od beginIndex (włącznie) do endIndex (wyłącznie).
indexOf(String str) i lastIndexOf(String str):
Zwracają indeks pierwszego/ostatniego wystąpienia podciągu w łańcuchu. Jeśli podciąg nie jest znaleziony, zwraca -1.
equals(Object obj):
Porównuje zawartość tego łańcucha z zawartością innego obiektu. Zwraca true, jeśli są równe.
equalsIgnoreCase(String anotherString):
Porównuje łańcuchy bez uwzględniania wielkości liter.
startsWith(String prefix) i endsWith(String suffix):
Sprawdzają, czy łańcuch zaczyna się lub kończy danym ciągiem znaków.
replace(char oldChar, char newChar) lub replace(CharSequence target, CharSequence replacement):
Zwraca nowy łańcuch, w którym wszystkie wystąpienia oldChar lub target są zastąpione przez newChar lub replacement.
trim():
Zwraca kopię łańcucha z usuniętymi białymi znakami na początku i końcu.
toLowerCase() i toUpperCase():
Zmieniają wielkość liter w łańcuchu.
split(String regex):
Dzieli łańcuch według podanego wyrażenia regularnego.
isEmpty():
Sprawdza, czy łańcuch jest pusty (długość wynosi 0).
valueOf() (statyczna metoda):
Konwertuje różne typy danych (np. int, char) na łańcuchy.
String:
String są niemutowalne, co oznacza, że po ich utworzeniu nie można ich zmienić. Każda operacja, która wydaje się modyfikować łańcuch (np. konkatenacja), faktycznie tworzy nowy obiekt String.StringBuilder:
StringBuilder są mutowalne. Można dodawać, usuwać i modyfikować zawartość obiektu bez tworzenia nowych obiektów.String w operacjach modyfikujących, szczególnie w intensywnych operacjach, takich jak budowanie łańcuchów w pętlach.StringBuilder jest zwykle lepszym wyborem niż StringBuffer.Często używane metody:
append():
Dodaje wartość do końca obecnej zawartości StringBuilder.
Jest przeciążona, by obsłużyć różne typy danych: String, char, int, long, float, double itp.
Przykład:
insert():
Wstawia wartość w określonej pozycji w StringBuilder.
Przykład:
delete() i deleteCharAt():
delete(int start, int end) usuwa podciąg znaków od indeksu start do indeksu end - 1.
deleteCharAt(int index) usuwa znak w określonym indeksie.
Przykład:
replace():
Zamienia podciąg znaków w określonym zakresie na inny ciąg znaków.
Przykład:
toString():
Konwertuje StringBuilder na String.
Przykład:
length():
Zwraca liczbę znaków w StringBuilder.
Przykład:
setLength():
Ustawia długość StringBuilder. Jeśli nowa długość jest krótsza niż obecna, ciąg zostanie obcięty. Jeśli jest dłuższy, dodane zostaną znaki o wartości \u0000.
Przykład:
charAt(), setCharAt():
charAt(int index) zwraca znak w określonym indeksie.
setCharAt(int index, char ch) ustawia znak w określonym indeksie.
Przykład:
reverse():
Odwraca kolejność znaków w StringBuilder.
Przykład:
StringBuffer:
StringBuilder, obiekty StringBuffer są mutowalne.StringBuilder, ale operacje są synchronizowane.StringBuffer może być odpowiednim wyborem.Metody dla StringBuffer są w większości analogiczne jak dla StringBuilder.
https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/Character.html
Klasa w programowaniu obiektowym w języku Java to podstawowy koncept i “struktura”formuła”, która pozwala na tworzenie obiektów.
Blueprint: Klasa jest jak “projekt” lub szablon, który opisuje, jakie zmienne (stany) i metody (zachowania) powinien posiadać obiekt tej klasy.
Enkapsulacja (hermatyzacja): Klasa kapsułkuje dane dla obiektu i funkcje, które operują na tych danych. To pozwala na ukrycie szczegółów implementacji i eksponowanie tylko niezbędnych interfejsów.
Konstruktor: Klasa może posiadać specjalne metody nazywane konstruktorami, które są używane do inicjalizacji obiektu podczas jego tworzenia.
Dziedziczenia: Klasa może dziedziczyć zmienne i metody z innej klasy. Dziedziczenie pozwala na tworzenie nowej klasy na bazie już istniejącej, co ułatwia ponowne wykorzystanie kodu.
Modyfikatory: Klasy mogą być opatrzone różnymi modyfikatorami, które decydują o dostępie do klasy oraz jej składników.
Zmienne instancyjne: Wewnątrz klasy można zdefiniować zmienne, które będą przechowywać stan obiektu.
Metody: Metody to funkcje zdefiniowane w klasie, które operują na zmiennych instancji i definiują zachowanie obiektu.
Klasy wewnętrzne: Java pozwala na definiowanie klas wewnątrz innych klas, co nazywane jest klasami wewnętrznymi.
Obiekt to podstawowy byt w programowaniu obiektowym. Jest to konkretna instancja klasy, która jest jak “projekt” lub “szablon”. Obiekty stanowią podstawę działania wielu aplikacji i systemów. Aby zrozumieć obiekty, warto je podzielić na trzy główne aspekty: stan, zachowanie i tożsamość.
Samochod, stan tego obiektu mógłby być reprezentowany przez takie zmienne jak marka, model, rokProdukcji, kolor itp.Samochod, przykładowe zachowania mogłyby obejmować przyspiesz(), zatrzymaj(), skręćWLewo() itp.Samochod mogą mieć taki sam stan (takie same marki, modele, kolory itp.), każdy z nich będzie miał unikalny adres pamięci, dzięki czemu można je odróżnić.Samochod, OsobaKontaktowa.KontoBankowe zamiast PrzetwarzanieTransakcji.public, private i protected.private) aby chronić je przed niepożądanym dostępem z zewnątrz.public.get lub set, a następnie nazwa zmiennej z wielkiej litery, np. getImie() lub setImie()./** ... */) do dokumentowania klas, zmiennych i metod. Dzięki temu inne osoby korzystające z Twojego kodu będą miały łatwy dostęp do opisu funkcjonalności.https://www.oracle.com/java/technologies/javase/codeconventions-fileorganization.html
https://google.github.io/styleguide/javaguide.html#s3.4.2-class-member-ordering
public static final zmienne).public class Car {
// 1. Deklaracje członków klasy
// a. Stałe
public static final int MAX_SPEED = 200;
// b. Zmienne statyczne
private static int totalCarsProduced;
// c. Zmienne instancji
private String make;
private String model;
private int year;
private int speed;
// 2. Konstruktory
public Car(String make, String model, int year) {
this.make = make;
this.model = model;
this.year = year;
this.speed = 0;
totalCarsProduced++;
}
// 3. Metody
// a. Metody fabrykujące (jeśli by były potrzebne, dla demonstracji)
public static Car createVintageCar(String make, String model) {
return new Car(make, model, 1960);
}
// b. Metody dostępowe (gettery i settery)
public String getMake() {
return make;
}
public void setMake(String make) {
this.make = make;
}
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public int getSpeed() {
return speed;
}
// c. Metody publiczne
public void accelerate() {
if (speed < MAX_SPEED) {
speed += 10;
}
}
public void decelerate() {
if (speed > 0) {
speed -= 10;
}
}
// d. Metody chronione (dla demonstracji, w tym przypadku mogą nie mieć sensu)
protected void resetCar() {
speed = 0;
}
// e. Metody prywatne
private void updateTotalCars() {
totalCarsProduced++;
}
// 4. Wewnętrzne klasy (dla demonstracji)
private class Engine {
private int horsepower;
private String type;
Engine(int horsepower, String type) {
this.horsepower = horsepower;
this.type = type;
}
public int getHorsepower() {
return horsepower;
}
public String getType() {
return type;
}
}
}W Javie, jeśli klasa nie ma zdefiniowanego żadnego konstruktora, kompilator dostarcza domyślny konstruktor bezargumentowy (nazywany również konstruktorem domyślnym). Ten konstruktor nie ma żadnego ciała i służy wyłącznie do tworzenia obiektów.
Jeśli jednak zdefiniujesz choć jeden konstruktor dla klasy, kompilator już nie dostarcza domyślnego konstruktora. W takim przypadku, jeśli chcesz mieć konstruktor bezargumentowy, musisz go jawnie zdefiniować.
public class Dog {
// Zmienne instancji
private String name;
private String breed;
// Metody
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getBreed() {
return breed;
}
public void setBreed(String breed) {
this.breed = breed;
}
}
// Główna klasa z metodą main do demonstracji
public class TestDog {
public static void main(String[] args) {
// Tworzenie obiektu klasy Dog przy użyciu domyślnego konstruktora
Dog myDog = new Dog();
// Ustawianie wartości za pomocą setterów, ponieważ nie mamy zdefiniowanego konstruktora z argumentami
myDog.setName("Rex");
myDog.setBreed("Golden Retriever");
// Wydrukowanie wartości
System.out.println("Name: " + myDog.getName());
System.out.println("Breed: " + myDog.getBreed());
}
}newOperator new w Javie odgrywa kluczową rolę w tworzeniu nowych obiektów i jest nieodłącznym elementem programowania obiektowego w tym języku.
new, system przydziela pamięć dla nowego obiektu w stercie (ang. heap). Sterta jest obszarem pamięci przeznaczonym do alokacji pamięci dla obiektów w czasie działania programu.new nie tylko alokuje pamięć, ale również inicjuje obiekt poprzez wywołanie odpowiedniego konstruktora klasy.new zwraca referencję do tego obiektu. Referencję tę można przypisać do zmiennej, która jest zmienną referencyjną odpowiedniego typu.new, można od razu użyć konstruktora klasy, aby zainicjować obiekt. Na przykład: new Dog("Rex") używa konstruktora klasy Dog, który przyjmuje jeden argument typu String.new jest również używany do tworzenia tablic w Javie. Na przykład: new int[5] tworzy tablicę pięciu elementów typu int.Operator kropki (wyboru składowej) . jest jednym z najczęściej używanych operatorów i ma wiele zastosowań w kontekście dostępu do składowych klasy lub obiektu.
Zastosowania:
Operator kropki pozwala na dostęp do pól (zmiennych instancji) oraz metod obiektu. Jeśli pole lub metoda są oznaczone jako public, można do nich bezpośrednio odwołać się za pomocą operatora kropki.
Można użyć operatora kropki do dostępu do statycznych składowych klasy (czyli tych, które są oznaczone słowem kluczowym static). W tym przypadku odnosimy się bezpośrednio do klasy, a nie do instancji klasy.
Operator kropki jest używany do odwoływania się do klas wewnątrz pakietów.
W sytuacjach, gdy chcemy się odwołać do konkretnej klasy lub składowej w ramach określonego pakietu, używamy operatora kropki.
W kontekście dziedziczenia, jeśli podklasa chce się odwołać do składowej klasy bazowej, która została przesłonięta w podklasie, można użyć słowa kluczowego super w połączeniu z operatorem kropki.
Jeśli klasa ma zagnieżdżoną klasę wewnętrzną, można odwołać się do niej za pomocą operatora kropki.
Bloki inicjujące w Javie to specjalne bloki kodu, które są wykonywane podczas tworzenia obiektu. Służą one do inicjalizacji zmiennych instancji oraz do wykonywania pewnych operacji przed wywołaniem konstruktora klasy.
Java oferuje dwa rodzaje bloków inicjujących:
Wartości domyślne:
Jeśli zmiennej instancji nie przypiszemy wartości, Java automatycznie przypisuje jej wartość domyślną w zależności od typu zmiennej:
int, float, double): 0boolean: falsechar: \u0000 (null)nullpublic class TestSample {
public static void main(String[] args) {
System.out.println("Main method started");
// Tworzenie obiektu klasy Sample
Sample sample = new Sample();
System.out.println("Instance Variable: " + sample.instanceVar);
}
}
class Sample {
// Zmienna instancji
public int instanceVar;
// Konstruktor
public Sample() {
System.out.println("Constructor executed");
}
// Blok inicjujący instancji
{
instanceVar = 10;
System.out.println("Instance block executed");
}
}nullWyjątek NullPointerException (NPE) pojawia się, gdy program próbuje odwołać się do obiektu lub wywołać metodę na referencji, która jest null.
Podstawowe zasady (na ten moment)
Inicjalizuj zmienne: - Gdy to możliwe, inicjalizuj zmienne w momencie ich deklaracji. - Unikaj pozostawiania zmiennych referencyjnych bez wartości (niewypełnionych).
Sprawdzaj obiekty przed użyciem: - Zawsze sprawdzaj, czy referencja nie jest null, zanim użyjesz jej do wywołania metody lub dostępu do pola.
Objects.requireNonNull(T obj):
obj nie jest null.null, metoda rzuci wyjątek NullPointerException.null, zostanie zwrócony bez zmian.Objects.requireNonNull(T obj, String message).null.Objects.requireNonNullElse(T obj, T defaultObj):
obj nie jest null.obj jest null, zwraca defaultObj jako wartość domyślną.obj nie jest null, zwraca obj.null.Modyfikatory dostępu w Javie określają zakres widoczności i dostępności składowych klasy (tj. pól, metod, konstruktorów, itp.). Istnieje cztery główne modyfikatory dostępu:
private:
private jest dostępna wyłącznie w obrębie klasy, w której została zdefiniowana.default (brak modyfikatora):
protected:
protected jest dostępna w obrębie jej klasy, w obrębie wszystkich klas w tym samym pakiecie, a także w subklasach (nawet jeśli są w innym pakiecie).public, ale mniej niż private i default.public:
public jest dostępna z każdej klasy, niezależnie od pakietu.