Programowanie obiektowe Wykład 01 Maciej Wołoszyn mailto:woloszyn@fatcat.ftj.agh.edu.pl 27 lutego 2008 Spis treści 1 Java 2 1.1 Najważniejsze cechy języka.......................... 2 1.2 Składnia..................................... 2 1.3 Przykładowy program.............................. 3 2 Typy danych 3 3 Operatory 5 4 Klasy 8 4.1 Składowe static................................ 11 4.2 Dostęp do składników.............................. 12 4.3 Dostęp do klas i nazwy plików źródłowych.................. 12 5 Klasy biblioteczne 12 6 Tablice 14 6.1 Tablice wielowymiarowe............................ 15 6.2 Klasa Arrays.................................. 16 7 Styl konwencje, nazewnictwo itp. 16 Proszę o przesyłanie na ten adres informacji o znalezionych błędach, literówkach oraz propozycji zmian i uzupełnień. Dokument przygotowano za pomocą systemu LATEX. Wszelkie prawa zastrzeżone. 1
Programowanie obiektowe. Wykład 01 2 1 Java język programowania zaprojektowany przez firmę Sun ( http://java.sun.com ) 1.1 Najważniejsze cechy języka niezależny od architektury programy napisane w języku Java można uruchamiać w wielu systemach operacyjnych komputerów, a także na różnych innych urządzeniach (np. telefony) kod źródłowy kompiluje się do postaci pośredniej (tzw. bytecode, uniwersalny dla wszystkich obsługiwanych systemów operacyjnych) do uruchomienia potrzebna jest wirtualna maszyna Javy (JVM, zależne od systemu operacyjnego środowisko uruchomieniowe; np. zawarte w pakiecie JSE firmy Sun) w efekcie także: mniejsza wydajność w porównaniu do języków typu C czy C++ ale stale poprawiana za pomocą mechanizmów takich jak just-in-time compilation (JIT) większe zużycie zasobów komputera zastosowanie metodologii obiektowej zaimplementowana od podstaw; pierwotnym zamiarem twórców Javy było zastąpienie C++ wbudowana obsługa m.in. sieci komputerowych, graficznego interfejsu użytkownika, wielowątkowości wraz z Javą dostarczana jest bardzo obszerna biblioteka klas 1.2 Składnia oparta na C i C++ : podobny sposób zapisu programu, definiowana zmiennych, funkcji, bloków instrukcji; identyczne instrukcje sterujące takie jak np.: if for while switch
Programowanie obiektowe. Wykład 01 3 1.3 Przykładowy program Plik MojProgram.java: // plik MUSI sie nazywac MojProgram.java! public class MojProgram { public static void main(string[] args) { System.out.println("[MojProgram!]"); odpowiednikiem występującej w C i C++ funkcji main(int argc, char* argv[]) jest zawarta w publicznie dostępnej klasie metoda public static void main(string[] args) od main rozpoczyna się wykonywanie aplikacji (innym rodzajem tworzonych w Javie programów są np. aplety programy działające zwykle na stronie WWW, w oknie przeglądarki internetowej) 1. kompilacja do postaci bytecode u: $ javac MojProgram.java wytworzenie pliku MojProgram.class (lub komunikaty o błędach kompilacji!) 2. uruchomienie programu następuje za pomoca JVM: $ java MojProgram [MojProgram!] 2 Typy danych proste (primitive types) int 32-bitowa liczba całkowita (zakres 2 31 2 31 1) byte 8-bitowa liczba całkowita ( 128 127) short 16-bitowa liczba całkowita ( 32768 32767) long 64-bitowa liczba całkowita (zakres 2 63 2 63 1) float 32-bitowa liczba zmiennoprzecinkowa (precyzja ok. 7 cyfr) double 64-bitowa liczba zmiennoprzecinkowa (precyzja ok. 15 cyfr) char 16-bitowy znak kodowany jako Unicode (inaczej niż w C++! łatwo operować na znakach narodowych itp.)
Programowanie obiektowe. Wykład 01 4 boolean typ logiczny (odpowiednik bool z C++), może przechowywać wartości true lub false... oraz typ void Uwaga: Java wymaga dokładnego przestrzegania zgodności typów, stąd np. do przechowywania wartości rzeczywistych zwykle najwygodniej używać tylko typu double Przykład: nie jest możliwe bezpośrednie (bez rzutowania) podstawienie wartości typu double do zmiennej float: // float fx = 1.2; /* ZLE! */ double dx = 1.2; /* OK */ zakresy ważności nazw są ograniczone podobnie jak w C i C++ nawiasami klamrowymi { nie jest dozwolone przesłanianie nazw, np. { char w = a ; { // char w = b ; /* ZLE */ obiekty (instancje klas) wszystkie dziedziczą po wspólnej, bazowej klasie Object (np. dzięki temu wszystkie mają metodę tostring()) są dostępne tylko poprzez referencje nigdy bezpośrednio! składają się z: pól (danych składowych) metod (funkcji składowych) tworzone są za pomocą operatora new Przykład: (klasa String pełni w Javie podobną rolę jak std::string w C++) String s = new String("abc"); System.out.println("napis=[" + s + "]"); napis=[abc] Instrukcja:
Programowanie obiektowe. Wykład 01 5 String s; tworzy tylko referencję nie odnosi się ona jeszcze do żadnego obiektu (nie została zainicjalizowana); błędna byłaby więc wtedy instrukcja: System.out.println("napis=["+s+"]"); (efekt błąd kompilacji: variable s might not have been initialized) String (klasa obsługująca napisy) jest przykładem jednej z bardzo wielu klas dostępnych w bibliotece Javy dla typów prostych, które same nie są obiektami, dostępne są klasy obudowujące (wrappers), np. double x = -0.5; Double obj = new Double(x); System.out.println("obj="+obj); obj=-0.5 dla klas obudowujących (opakowujących) jest używany mechanizm automatycznego opakowywania i rozpakowywania double x = 3.0; Double obj = x / 2.0; double y = obj / 2.0; System.out.println("y="+y); y=0.75 swoich odpowiedników wśród typów prostych nie mają klasy służące do operacji arytmetycznych z dużą dokładnością: BigInteger liczby całkowitej dowolnego rozmiaru BigDecimal liczby ułamkowe z dowolną precyzją pozwalają one na operacje dostępne dla innych typów reprezentujących liczby, z tym że zamiast operatorów należy użyć odpowiednich metod 3 Operatory Java zapewnia standardowy zestaw operatorów dla typów prostych (np. arytmetyczne + - / *, operator przypisania = itd.)
Programowanie obiektowe. Wykład 01 6 dla obiektów mają zastosowanie tylko operatory = ==!= operatorów nie można przeładowywać dodatkowo klasa String pozwala na używanie operatorów + oraz += String s = new String("abc"); String t = new String("def"); System.out.println(s+t); abcdef jeżeli wyrażenie rozpoczyna się od obiektu typu String, to następujące po operatorze + wyrazy także muszą być typu String w razie potrzeby kompilator będzie się starał znaleźć reprezentację obiektu lub typu protego w postaci napisu double x=-1.2; String u = "x="+x; System.out.println(u); x=-1.2 operator przypisania zastosowany dla obiektów kopiuje referencje! również operatory porównania == i!= w przypadku obiektów porównują same referencje ( adresy ), a nie to, na co one wskazują (zawartość obiektów)! Przykład: class Znak { char z; Znak a = new Znak(); Znak b = new Znak(); a.z = A ; b.z = B ; System.out.println("a="+a.z+" b="+b.z); b = a; System.out.println("a="+a.z+" b="+b.z); a.z = C ; System.out.println("a="+a.z+" b="+b.z); a=a b=b a=a b=a a=c b=c
Programowanie obiektowe. Wykład 01 7 Znak a = new Znak(); Znak b = new Znak(); a.z = q ; b.z = q ; System.out.println(a==b); b=a; System.out.println(a==b); false true do porównywania obiektów tworzonych z klas bibliotecznych można posłużyć się metodą equals(), która zwykle porównuje zawartość obiektów String s = new String("abc"); String t = new String("abc"); System.out.println(s==t); System.out.println(s.equals(t)); false true operator rzutowania: (typdocelowy) może być używany pomiędzy dowolnymi typami prostymi z wyjątkiem boolean, przy czym jawne rzutowanie jest wymagane tylko gdy istnieje groźba utraty informacji; w przypadku obiektów rzutowanie jest możliwe tylko wewnątrz jednej rodziny (tzn. powiązanych relacją dziedziczenia) int n = 1; double z = n; //OK //n = z; /* ZLE */ n = (int)(z+1.9); System.out.println("z="+z+" n="+n); z=1.0 n=2 brak jest operatora w rodzaju sizeof w Javie jest on zbędny: poszczególne typy mają dobrze zdefiniowane rozmiary (więc nie ma potrzeby sprawdzania np. liczby bajtów zajmowanych przez zmienną typu int).
Programowanie obiektowe. Wykład 01 8 4 Klasy definicja: class Nazwa {... pola, metody... pola mogą być zarówno typów prostych, jak i referencjami do obiektów Przykład: class CA { int i; String s; referencje muszą zostać zainicjalizowane przed użyciem, np. z wykorzystaniem operatora new w konstruktorze odniesienie się do składników klasy następuje poprzez operator. public static void main(string[] args) { CA ca = new CA(); ca.i = 5; ca.s = "to jest CA"; System.out.println( ca.s + ", ca.i = " + ca.i); to jest CA, ca.i = 5 każde pole typu prostego jest domyślnie inicjalizowane wartością: 0 w przypadku typów liczbowych false dla typu boolean znakiem o kodzie \u0000 jeśli typem jest char Uwaga: Inicjalizacja taka dotyczy tylko pól (danych składowych) klas! niezainicjalizowane referencje mają wartość null pola mogą być inicjalizowane równocześnie z deklaracją, np. class CA { int x = 5;
Programowanie obiektowe. Wykład 01 9 lub za pomocą tzw. bloku inicjalizacyjnego: class CA { int x; { x = 5; funkcje można w Javie definiować tylko jako metody wewnątrz klas class CB { void print(string s) { System.out.println(s); class Program { public static void main(string[] args) { String w = "ABC"; CB o = new CB(); o.print(w); ABC argumenty są przesyłane do metod poprzez wartość ale dla obiektów tą wartością jest referencja! class CA { int x = 5; class CB { void print(ca c){ System.out.println("x=" + c.x); c.x = 0; class Program { public static void main(string[] args) { CA a = new CA(); CB b = new CB(); b.print(a);
Programowanie obiektowe. Wykład 01 10 System.out.println("teraz x=" + a.x); x=5 teraz x=0? jaki skutek miałoby użycie poniższej metody zdefiniowanej w klasie CB? void swap(ca a, CA b) { CA t = a; a = b; b = t; Odpowiedź: żaden! CA w = new CA(); CA v = new CA(); w.x=-1; v.x=2; System.out.println(w.x + " " +v.x); b.swap(v,w); System.out.println(w.x + " " +v.x); -1 2-1 2 dla porównania: jeśli do klasy CA dodałoby się metodę setx class CA { int x = 5; void setx(ca c) { x = c.x; to w klasie CB zdefiniować można następującą metodę swap2: void swap2(ca a, CA b) { CA t = new CA(); t.setx(a); a.setx(b); b.setx(t);
Programowanie obiektowe. Wykład 01 11 w.x=-1; v.x=2; System.out.println(w.x + " " +v.x); b.swap2(v,w); System.out.println(w.x + " " +v.x); -1 2 2-1? Dlaczego tym razem zamiana się powiodła? 4.1 Składowe static metody static mogą być uruchamiane nawet gdy nie istnieją żadne obiekty danej klasy; definiuje się je wewnątrz klasy class CC { static void print(double x){ System.out.println("x="+x); wywołanie następuje poprzez użycie konstrukcji nazwaklasy.nazwametody() Przykład: x=2.3 CC.print(2.3); Uwaga: metody static (np. main) nie mogą się bezpośrednio odnosić do składowych, które nie są statyczne! pola static również nie są związane z konkretną instancją klasy; deklaruje się je wewnątrz klasy i mogą być inicjalizowane równocześnie z deklaracją class CD { static int n=0; CD.n = -3; CC.print(CD.n);
Programowanie obiektowe. Wykład 01 12 x=-3.0 przykładem statycznego pola jest składnik out klasy System dlatego mogliśmy wywoływać dla niego metodę println, mimo że nie tworzyliśmy żadnego obiektu klasy System System.out.println( "System.out= " + System.out ); System.out= java.io.printstream@675b7986 4.2 Dostęp do składników określany znanymi z C++ słowami kluczowymi: public protected private należy je umieszczać każdorazowo przed polem lub metodą, których mają dotyczyć w Javie nie ma natomiast możliwości deklarowania klas lub metod zaprzyjaźnionych brak słów kluczowych private, protected i public skutkuje jeszcze innym, domyślnym sposobem ograniczenia dostępu: składnik taki będzie dostępny jedynie dla klas z tego samego pakietu (zwykle klas w tym samym pliku i innych plikach z tego samego katalogu), dla innych będzie się zachowywał tak, jakby był typu private jest to tzw. dostęp pakietowy (package access) protected umożliwia dostęp do składników nie tylko klasom potomnym, ale także innym klasom z tego samego pakietu 4.3 Dostęp do klas i nazwy plików źródłowych klasy mogą być deklarowane jako public (ogólnie dostępne) lub bez żadnego modyfikatora (dostępne w tym samym pakiecie) klasę publiczną należy umieszczać w pliku o nazwie zgodnej z nazwą klasy; w tym samym pliku mogą się znajdować również definicje innych (niepublicznych) klas 5 Klasy biblioteczne przed użyciem klas dodatkowych (tzn. spoza pakietu java.lang) dostępnych z bibliotek Javy (lub własnych pakietów) należy je dołączyć korzystając z polecenia: import nazwapakietu.nazwaklasy ; lub odnosić się do nich w kodzie poprzez pełną nazwę, np. java.util.vector
Programowanie obiektowe. Wykład 01 13 import java.util.date; class Program { public static void main(string[] args){ Date d = new Date(); System.out.println("Dzisiaj= "+d); Dzisiaj= Wed Feb 27 10:58:16 CEST 2008 oprócz importowania pojedynczych klas można również dodać cały pakiet, np. w poprzednim przykładzie linię import java.util.date; można zastąpić instrukcją import java.util.*; domyślnie dostępne są wszystkie klasy z pakietu java.lang należą do nich m.in.: String Math klasa zawierająca podstawowe funkcje matematyczne takie jak np.: sin(double x) sqrt(double x) oraz stałe: E liczba e PI liczba π double x = Math.PI; double y; y = Math.cos(x/2); System.out.println("cos(PI/2)="+y); cos(pi/2)=6.123233995736766e-17 pełną dokumentację bibliotek Javy można pobrać do zainstalowania lub przeglądać online na stronach http://java.sun.com/javase/reference/api.jsp (np. dla wersji J2SE 5.0 pod adresem http://java.sun.com/j2se/1.5.0/docs/ api/ a dla Java SE 6 http://java.sun.com/javase/6/docs/api/ )
Programowanie obiektowe. Wykład 01 14 6 Tablice są obiektami definiowanymi za pomocą operatora [] typ[] nazwaobiektu; (definiuje się w ten sposób jak zwykle referencję do obiektu! nie została zarezerwowane jeszcze żadna pamięć) tworzone są operatorem new int[] t1 = new int[5]; lub jednocześnie z inicjalizacją int[] t2 = {1,2,3; String[] tab = { new String("abc"), new String("def") ;? Co byłoby efektem wykonania instrukcji t1=t2;? każda tablica posiada pole o nazwie length zawierające informację o jej rozmiarze (poszczególne elementy mają numery od 0 do length-1) for(int i=0;i<tab.length;i++) System.out.print(tab[i]+" "); for(int i=0;i<t1.length;i++) System.out.print(t1[i]+"#"); for(int i=0;i<t2.length;i++) System.out.print(t2[i]+":"); abc def 0#0#0#0#0#1:2:3: wyjście poza tablicę skutkuje natychmiastowym wystąpieniem sytuacji wyjątkowej java.lang.arrayindexoutofboundsexception rozmiar tablicy może być obliczany w trakcie wykonywania programu int N = 4; /*... */ double[] z = new double[n*10]; utworzenie tablicy dla obiektów tworzy w rzeczywistości tylko tablicę referencji same obiekty też dopiero wymagają utworzenia za pomocą new!
Programowanie obiektowe. Wykład 01 15 class Znak { char z= x ; Znak[] ts = new Znak[3]; //System.out.println(ts[1].z); /* ZLE */ for(int i=0;i<ts.length;i++) ts[i] = new Znak(); System.out.println(ts[1].z); x próba dostępu do nieutworzonego elementu tablicy kończy się wystąpieniem wyjątku java.lang.nullpointerexception 6.1 Tablice wielowymiarowe obiektem zawartym w każdym elemencie jednowymiarowej tablicy może być kolejna tablica łatwo można tworzyć wielowymiarowe tablice, także o różnych rozmiarach poszczególnych podtablic (np. tablica dwuwymiarowa o wierszach różnej długości) int[][] t = { {1,2,3, {4,5 ; for(int i = 0; i < t.length; i++) for(int j = 0; j < t[i].length; j++) System.out.println("t[" + i + "][" + j + "] = " + t[i][j]); t[0][0] = 1 t[0][1] = 2 t[0][2] = 3 t[1][0] = 4 t[1][1] = 5 String[][] ts = new String[2][2]; for(int i = 0; i < ts.length; i++) for(int j = 0; j < ts[i].length; j++) { ts[i][j] = new String("ts"+i+j); System.out.println("ts[" + i + "][" + j + "] = " + ts[i][j]); ts[0][0] = ts00 ts[0][1] = ts01 ts[1][0] = ts10 ts[1][1] = ts11
Programowanie obiektowe. Wykład 01 16 6.2 Klasa Arrays pakiet java.util.* zbiór statycznych metod do typowych operacji na tablicach (np. wyszukiwanie, sortowanie, porównywanie) int[] t = {4,2,1,3; Arrays.sort(t); System.out.println(Arrays.toString(t)); [1, 2, 3, 4] 7 Styl konwencje, nazewnictwo itp. najczęściej przyjmowana praktyka to nazywanie klas z dużej litery, a jeśli nazwa składa się z kilku słów to łączenie ich w jeden napis, z zaznaczeniem pierwszych znaków dużymi literami, np.: MojaBardzoPotrzebnaKlasa nazwy metod tworzy się zwykle podobnie, z tym że zaczynając od małej litery: pewnapozytecznametoda() nazwy zmiennych tworzone są na tej samej zasadzie co nazwy metod; zalecane jest unikanie nazw rozpoczynających się od znaku podkreślenia stałe mają nazwy pisane samymi dużymi literami, np. Math.PI jeśli składają się z kilku słów, to rozdziela się je znakiem podkreślenia, np. WAZNA_STALA_MATEMATYCZNA Więcej zaleceń można znaleźć w dokumencie Code Conventions for the Java Programming Language http://java.sun.com/docs/codeconv/