Wykład 1
Ewentualne braki należy opanować w samodzielnym zakresie.
W razie problemów zapraszam na konsultacje.
Programowanie:
to instruowanie komputera, co ma robić.
to co robi “programista” gdy pisze “program”.
przekazanie fragmentu rzeczywistości do komputera.
Paradygmat programowania — sposób patrzenia programisty na przepływ sterowania i wykonywanie programu komputerowego.
Przeanalizujmy przykłady.
Python:
C
C
#include <stdio.h>
#include <string.h>
struct Laptop {
char model[30];
float cena;
};
struct Laptop initLaptop(char* model, float cena) {
struct Laptop nowyLaptop;
strncpy(nowyLaptop.model, model, sizeof(nowyLaptop.model) - 1);
nowyLaptop.model[sizeof(nowyLaptop.model) - 1] = '\0';
nowyLaptop.cena = cena;
return nowyLaptop;
}
void pokazLaptop(struct Laptop laptop) {
printf("Model: %s\n", laptop.model);
printf("Cena: %.2f\n", laptop.cena);
}
void zmniejszCene(struct Laptop* laptop) {
laptop->cena *= 0.95;
}
int main() {
struct Laptop mojLaptop = initLaptop("Dell XPS 15", 5000.0);
pokazLaptop(mojLaptop);
zmniejszCene(&mojLaptop);
printf("Po obnizce ceny:\n");
pokazLaptop(mojLaptop);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Ksiazka {
char tytul[50];
int liczba_stron;
} Ksiazka;
Ksiazka* initKsiazka(const char *tytul, int liczba_stron) {
if(strlen(tytul) < 5 || liczba_stron <= 50)
return NULL;
Ksiazka* nowa_ksiazka = (Ksiazka*)malloc(sizeof(Ksiazka));
strcpy(nowa_ksiazka->tytul, tytul);
nowa_ksiazka->liczba_stron = liczba_stron;
return nowa_ksiazka;
}
void pokazKsiazka(Ksiazka ksiazka) {
printf("Tytul: %s, Liczba stron: %d\n", ksiazka.tytul, ksiazka.liczba_stron);
}
void dodajStrony(Ksiazka *ksiazka) {
ksiazka->liczba_stron += 10;
}
int main() {
Ksiazka* ksiazka1 = initKsiazka("Wojna i pokoj", 1200);
if(ksiazka1 != NULL) {
pokazKsiazka(*ksiazka1);
dodajStrony(ksiazka1);
pokazKsiazka(*ksiazka1);
} else {
printf("Nie udalo sie utworzyc ksiazki.\n");
}
free(ksiazka1);
return 0;
}
Abstrakcja: Programowanie obiektowe pozwala na modelowanie rzeczywistych obiektów z życia codziennego w postaci klas i obiektów w programie. Dzięki temu, tworzenie i zarządzanie złożonymi systemami staje się bardziej intuicyjne.
Enkapsulacja: Klasy (formuły na obiekty) mogą ukrywać swoje dane i metody przed innymi klasami, co zwiększa bezpieczeństwo i chroni przed nieautoryzowanym dostępem.
Dziedziczenie: Dzięki dziedziczeniu możemy tworzyć nowe klasy na podstawie już istniejących, dziedzicząc ich atrybuty i metody. Umożliwia to ponowne wykorzystanie kodu i organizuje kod w hierarchiczny sposób.
Polimorfizm: Różne klasy mogą definiować metody o tej samej nazwie, ale zachowujące się inaczej w zależności od klasy. Polimorfizm ułatwia rozszerzanie i modyfikowanie kodu.
Modularność: Programowanie obiektowe promuje podział aplikacji na mniejsze, niezależne moduły (klasy), co ułatwia zarządzanie, testowanie i rozwijanie oprogramowania.
Zwiększenie czytelności
Elastyczność
House
johnHouse
main
.Klasa – częściowa lub całkowita definicja dla obiektów. Definicja obejmuje dopuszczalny stan obiektów oraz ich zachowania. Obiekt, który został stworzony na podstawie danej klasy nazywany jest jej instancją. Klasy mogą być typami języka programowania - przykładowo, instancja klasy Owoc będzie mieć typ Owoc. Klasy posiadają zarówno interfejs, jak i strukturę. Interfejs opisuje, jak komunikować się z jej instancjami za pośrednictwem metod, zaś struktura definiuje sposób mapowania stanu obiektu na elementarne atrybuty.
Obiekt - jest to struktura zawierająca:
(Źródło: Wikipedia.)
1991 rok: W firmie Sun Microsystems powstał projekt o nazwie “Green Team”, kierowany przez Jamesa Goslinga. Początkowy cel to stworzenie języka dla cyfrowych urządzeń konsumenckich, takich jak telewizory czy telefony.
1995 rok: Pierwsza oficjalna wersja Javy - Java 1.0, została zaprezentowana publicznie. Jej celem było zapewnienie “Napisz raz, uruchom wszędzie” (ang. “Write Once, Run Anywhere”).
1997 rok: Wydanie Java 1.1 przynosi wiele nowości, w tym pakiet AWT (Abstract Window Toolkit) umożliwiający tworzenie graficznych interfejsów użytkownika.
2000 rok: Debiut Java 2 (J2SE), wraz z wprowadzeniem wielu kluczowych technologii, takich jak Swing, Collections Framework i Java Naming and Directory Interface (JNDI).
2004 rok: Wydanie Javy 5 (lub Java 1.5). Wprowadzono wiele ważnych uaktualnień, takich jak generyki, metadata (adnotacje) oraz usprawnioną pętlę for (for-each).
2006 rok: Sun Microsystems udostępnia Javę jako wolne oprogramowanie na licencji GNU General Public License (GPL).
2010 rok: Firma Oracle przejmuje Sun Microsystems, stając się głównym opiekunem technologii Java.
Najnowsza wersja LTS 21 - 19 września 2023.
Dokumentacja https://docs.oracle.com/en/java/javase/21/docs/api/index.html
Klasy: Nazwy klas powinny zaczynać się wielką literą. Jeśli nazwa składa się z kilku słów, każde kolejne słowo powinno zaczynać się wielką literą. Nie używa się podkreślników. Przykład: UserData
, StringBuilder
.
Interfejsy: Tak samo jak klasy, nazwy interfejsów powinny zaczynać się wielką literą i używać notacji wielbłądzia. Przykład: Listenable
, Serializable
.
Metody: Nazwy metod zaczynają się małą literą, a każde kolejne słowo z wielkiej. Przykład: calculateTotal()
, getUserData()
.
Zmienne: Podobnie jak metody, nazwy zmiennych zaczynają się małą literą, a każde kolejne słowo z wielkiej. Przykład: totalCount
, userData
.
Stałe: Stałe (czyli zmienne, które są final
i static
) pisane są wielkimi literami, a słowa oddzielane są podkreślnikami. Przykład: MAX_VALUE
, PI
.
Pakiety: Nazwy pakietów powinny być pisane małymi literami. Jeśli pakiet składa się z kilku segmentów, powinny one być odseparowane kropkami. Zaleca się również, aby nazwy pakietów były unikalne, np. poprzez dodanie nazwy firmy lub domeny jako prefixu. Przykład: com.mycompany.mypackage
.
Typy generyczne: Jednoliterowe nazwy typów generycznych są powszechnie używane, chociaż nie jest to obowiązkowe. Typowy przykład to T
w definicji klas i metod generycznych.
main
Modyfikator dostępu: Metoda main
musi być public
, aby JVM (Java Virtual Machine) mógł ją wywołać z poza klasy, w której jest zdefiniowana.
Modyfikator statyczny: Metoda musi być static
, ponieważ JVM musi mieć możliwość jej wywołania bez tworzenia instancji klasy.
Zwracany typ: Metoda main
nie zwraca wartości, więc jej typem zwracanym jest void
.
Nazwa: Nazwą metody musi być dokładnie main
.
Parametry: Metoda main
przyjmuje jeden argument, którym jest tablica ciągów znaków (String[]
). Zwykle nazywa się go args
, ale możesz użyć innej nazwy, jeśli chcesz.
Nazwa pliku: Nazwa pliku musi dokładnie odpowiadać nazwie klasy lub interfejsu, który jest w nim zdefiniowany, z zachowaniem wielkości liter.
Rozszerzenie pliku: Pliki źródłowe Javy mają rozszerzenie .java
.
Jedna publiczna klasa lub interfejs na plik: Jeśli klasa lub interfejs jest zdefiniowany jako public
, musi być to jedyna publiczna klasa lub interfejs w tym pliku, a nazwa pliku musi dokładnie odpowiadać nazwie tej klasy lub interfejsu. Na przykład, jeśli masz publiczną klasę o nazwie MyClass
, musi ona być zdefiniowana w pliku o nazwie MyClass.java
.
Niepubliczne klasy: Możesz mieć wiele niepublicznych klas w jednym pliku źródłowym, ale pamiętaj, że nadal obowiązuje konwencja, że tylko jedna klasa lub interfejs może być publiczny w danym pliku.
Pliki z główną metodą: Jeśli klasa zawiera metodę main
(punkt wejścia do programu), zalecane jest, aby taka klasa była jedyną publiczną klasą w pliku, choć nie jest to wymogiem.
Komentarze jednoliniowe: Używane do krótkich uwag lub komentarzy dotyczących pojedynczej linii kodu.
Komentarze wieloliniowe: Używane do opisów wymagających kilku linii. Mogą one pojawiać się w dowolnym miejscu w kodzie.
Komentarze dokumentacyjne (JavaDoc): Używane do tworzenia dokumentacji API z kodu źródłowego. Narzędzie javadoc
może przetwarzać te komentarze i generować sformatowaną dokumentację w postaci stron HTML.
Nie nadużywaj komentarzy: Dobrze napisany kod powinien być na tyle czytelny, że nie wymaga nadmiernego komentowania. Nazwy zmiennych, metod i klas powinny być wyraźne i opisowe.
Unikaj komentarzy oczywistych: Komentarze takie jak
i++; // zwiększ i o 1
są zbędne i tylko zaśmiecają kod.
Utrzymuj aktualność komentarzy: Upewnij się, że komentarze odzwierciedlają aktualny stan i funkcjonalność kodu. Stare, nieaktualne komentarze mogą wprowadzać w błąd czytającego.
Używaj komentarzy do wyjaśnienia “dlaczego”: Często bardziej wartościowe niż komentarze mówiące “co robi kod”, są te wyjaśniające “dlaczego kod działa w taki sposób”. Mogą one pomóc innym programistom zrozumieć założenia czy trudne decyzje projektowe.
Java oferuje zestaw typów podstawowych (nazywanych też typami prostymi), które są używane do reprezentacji prostych wartości, takich jak liczby całkowite, liczby zmiennoprzecinkowe, znaki czy wartości logiczne.
byte
: 8-bitowa wartość liczby całkowitej; zakres od \(-128\) do \(127\).short
: 16-bitowa wartość liczby całkowitej; zakres od \(-32,768\) do \(32,767\).int
: 32-bitowa wartość liczby całkowitej; zakres od \(-2^{31}\) do \(2^{31}-1\).long
: 64-bitowa wartość liczby całkowitej; zakres od \(-2^{63}\) do \(2^{63}-1\).float
: 32-bitowa wartość liczby zmiennoprzecinkowej (jednokrotnej precyzji). Zaleca się używanie sufiksu F
lub f
przy inicjalizacji wartości stałych.double
: 64-bitowa wartość liczby zmiennoprzecinkowej (podwójnej precyzji). Jest to domyślny typ dla wartości zmiennoprzecinkowych w Javie.char
: Reprezentuje pojedynczy znak w standardzie Unicode i zajmuje 16 bitów. Znaki są zamykane w pojedynczych cudzysłowach, np. 'A'
.boolean
: Reprezentuje wartość prawda/fałsz. Może przyjmować tylko jedną z dwóch wartości: true
lub false
.Uwagi:
boolean
) ma odpowiadającą mu klasę opakowującą w pakiecie java.lang
(np. Integer
dla int
, Double
dla double
itp.). Klasy te są używane, gdy potrzebujemy reprezentować typ podstawowy jako obiekt, oraz oferują wiele pomocniczych metod do pracy z danym typem.0
dla typów liczbowych, false
dla boolean
), ale wartości te są ustawiane domyślnie tylko dla zmiennych klasowych lub instancyjnych, nie dla lokalnych zmiennych wewnątrz metod.public class Main {
public static void main(String[] args) {
int localVar; // zmienna lokalna niezainicjalizowana
// Poniższa linia spowoduje błąd kompilacji, ponieważ próbujemy użyć zmiennej,
// która nie została zainicjalizowana
// System.out.println(localVar);
localVar = 10; // inicjalizacja zmiennej lokalnej
System.out.println(localVar); // teraz jest w porządku, ponieważ zmienna
// została zainicjalizowana
}
}
W języku Java operacje wyjścia na konsolę odnoszą się głównie do wydruków tekstowych prezentowanych użytkownikowi na standardowym wyjściu (czyli zazwyczaj konsoli terminala).
System.out.print() i System.out.println():
System.out.print("Tekst")
: Drukuje podany tekst na konsoli bez przechodzenia do nowej linii.System.out.println("Tekst")
: Drukuje podany tekst na konsoli i przechodzi do nowej linii.Przykład:
Wyjście:
Witaj, świecie!
System.out.printf(): Pozwala na formatowane wyjście. Umożliwia wstawianie zmiennych w określone miejsca w tekście oraz kontrolowanie sposobu ich prezentacji.
Przykład:
double cena = 12.5;
int ilosc = 5;
System.out.printf("Cena: %.2f, Ilość: %d, Łącznie: %.2f", cena, ilosc, cena * ilosc);
Wyjście:
Cena: 12.50, Ilość: 5, Łącznie: 62.50
Metoda System.out.printf()
w Javie oraz funkcja printf()
w języku C są do siebie podobne pod względem ogólnego przeznaczenia i użycia, ponieważ obie służą do formatowanego wydruku napisów i są inspirowane tym samym konceptem. Niemniej jednak, istnieje kilka różnic w używaniu tych funkcji/metod, zarówno pod względem składni, jak i funkcjonalności, które mogą wpłynąć na to, jak są używane w obu językach.
Formatowanie: dokumentacja.
Klasa Scanner
jest często używana do wczytywania danych wejściowych z konsoli, ponieważ jest łatwa w użyciu i oferuje szeroki zakres funkcji do wczytywania różnych typów danych.
Inicjalizacja: Aby użyć klasy Scanner
, najpierw musisz ją zaimportować z pakietu java.util
, a następnie utworzyć jej obiekt, używając System.in
jako źródła wejściowego.
Wczytywanie danych:
Wczytywanie całego wiersza tekstu:
Wczytywanie pojedynczego słowa:
Wczytywanie danych liczbowych:
Wczytywanie wartości logicznych:
Zamykanie skanera: Po zakończeniu wczytywania danych z konsoli warto zamknąć obiekt Scanner
, aby zwolnić zasoby.
Więcej info: w dokumentacji.
Jeśli nie przypiszesz wartości początkowej do zmiennej podczas deklaracji, dla zmiennych lokalnych musisz to zrobić przed ich pierwszym użyciem. W przeciwnym razie kompilator zgłosi błąd. Zmienne instancji (pola klasy) otrzymują domyślne wartości.
var
Słowo kluczowe var
zostało wprowadzone w Javie 10 w celu poprawy czytelności kodu poprzez lokalne inferencje typów dla deklaracji zmiennych. Umożliwia to deklarowanie zmiennych bez konieczności jawnego podawania ich typu, o ile można jednoznacznie wywnioskować typ zmiennej na podstawie przypisywanej jej wartości.
Lokalne inferencje typów: var
może być używane tylko do deklaracji lokalnych zmiennych (wewnątrz metod, bloków, pętli itp.), inicjalizowanych zmiennych dla instrukcji for
oraz zmiennych lokalnych w try-with-resources.
Nie można używać z wartościami null
: Ponieważ var
opiera się na inferencji typów, nie można zadeklarować zmiennej jako var
i jednocześnie przypisać jej wartości null
, ponieważ kompilator nie będzie mógł wywnioskować typu.
var
nie jest dozwolone dla deklaracji pól klasy, sygnatur metod ani jako typ zwracany.Czytelność kodu: Używanie var
może poprawić czytelność, zwłaszcza gdy typ zmiennej jest oczywisty z kontekstu lub kiedy typ właściwy jest długi i skomplikowany (np. typy generyczne). Jednak w innych sytuacjach jawnie podane typy mogą być bardziej czytelne. Należy stosować var
z rozwagą.
Nie można używać dla zmiennych bez inicjalizacji: Deklaracja zmiennej z użyciem var
musi odbywać się jednocześnie z jej inicjalizacją.
Przykład:
Deklaracja: Używając modyfikatora final
podczas deklarowania zmiennej, sprawiamy, że staje się ona stałą. Oznacza to, że jej wartość nie może zostać zmieniona po pierwszym przypisaniu.
Inicjalizacja: Stała zmienna musi być zainicjowana w momencie jej deklaracji lub w konstruktorze (w przypadku zmiennych instancji).
Nazewnictwo: Konwencją jest nazywanie stałych zmiennych używając wielkich liter i podkreślników, aby łatwo je rozpoznać w kodzie, choć to nie jest wymogiem języka.