(Microsoft PowerPoint - java1.ppt [tryb zgodno\234ci])

Transkrypt

(Microsoft PowerPoint - java1.ppt [tryb zgodno\234ci])
Programowanie w
środowiskach graficznych
Wykład 1
Radosław Wajman
Krzysztof Grudzień
Katedra Informatyki Stosowanej, PŁ
Język java
Rok 1990, Bill Joy:
„utworzenie obiektowego środowiska w oparciu o
C++”
Język OAK (Object Application Kernel), 1991
Projekt Green,
James Gosling, Patrick Naughton, Mike Sheridan
Sun Developer Network
http://java.sun.com/docs/books/tutorial/java/index.html
Środowisko Java
Obiektowy język java (podobieństwo do C++);
Nazwa pliku źródłowego nazwa.java (nazwa –
to nazwa klasy – publicznej -zdefiniowanej w pliku);
Kompilator: *.java kod B: *.class;
Maszyna wirtualna (JVM);
Tworzenie kodu wykonywalnego „w locie”
Just-In-Time
Biblioteka Javy.
Usytuowanie systemu Java
Przetwarzanie programów użytkownika
Cechy języka Java
automatyczne odśmiecanie (garbage
collection)
nie dopuszcza arytmetyki wskaźnikowej
ścisła kontrola typów (konwersje)
obsługa wyjątków
wbudowane elementy współbieżności
Przykład
Programem w języku Java jest aplikacja
(application), aplet (applet) lub servlet (server
applet).
Aplikacja jest programem samodzielnym, zaś aplet
jest programem wbudowanym (np. w przeglądarkę
WWW) i wykonywanym po stronie klienta – servlet
po stronie serwera.
Każda aplikacja musi zawierać dokładnie jeden
moduł źródłowy nazywany modułem głównym
aplikacji, którego klasa zawiera publiczną funkcję
klasy
Przykład
public class Hello {
public static void main(String args[])
{
System.out.print("Hello, World!\n");
} //end main
} // end Hello
Kompilacja i uruchamianie
javac Hello.java B-kod: Hello.class
Interpretator:
java Hello
Jak działa interpretator?
wyszuka plik o nazwie Hello.class,
czy klasa Hello zawiera publiczną metodę
statyczną main
wykona instrukcje zawarte w bloku main.
W języku Java każda instrukcja kończy się
średnikiem, który pełni rolę symbolu
terminalnego.
Jak działa interpretator?
do metody main jako parametr jest przekazywana (z
wiersza rozkazowego) tablica obiektów (łańcuchów)
klasy String; metoda main nie zwraca wyniku
(typem zwracanym jest void);
Ciało main zawiera jedną instrukcję;
System.out.print("Hello, World!\n");
Jak działa interpretator?
Słowo System jest nazwą klasy w
standardowym środowisku języka.
Klasa System zawiera statyczny obiekt
składowy typu PrintStream o nazwie out
wywołanie System.out oznacza pisanie do
standardowego strumienia wyjściowego.
Klasa PrintStream zawiera szereg przeciążeń
metody o nazwie print (tu:parametr typu String).
Kompilator
automatycznie
konwertuje
"Hello, World\n" obiekt klasy String;
odnośnik (referencja) do tego obiektu
przekazywana do metody System.out.print().
jest
Metoda print() generuje jeden wiersz wyjściowy i
powraca do metody main, która kończy wykonanie.
!!!
w języku Java wszystkie stałe, zmienne i
funkcje są elementami składowymi klas;
nie
ma
wielkości
globalnych,
definiowanych poza klasą.
nie deklaruje się metod (funkcji) składowych
jako rozwijalnych (inline) bądź nie –
decyzja należy do kompilatora.
package moje.aplikacje;
import javax.swing.*;
import java.awt.Container;
Określenie nazwy pakietu, do którego należą
klasy zdefiniowane w tym pliku. Można opuścić.
Zewnętrzne pakiety (ew. pojedyncze klasy lub interfejsy), z
których korzystamy w naszym programie. Można uważać ten
element jako odpowiednik dyrektywy #include w C/C++.
class PierwszyGUI extends JFrame
{
public PierwszyGUI ()
{
...
}
}
Definicje klas (klasy mogą dziedziczyć,
jak w tym przykładzie).
Definicja konstruktora.
Inna klasa. Posiada składniki, które mogą być inicjalizowane.
public class KlasaStartowa
{
PierwszyGUI ob1;
PierwszyGUI ob2 = new PierwszyGUI ();
public static void main (String[] args)
{
...
}
}
Metoda main klasy startowej. To od niej
rozpoczyna się wykonywanie aplikacji.
Musi być to metoda public static !
Aplikacja graficzna
import javax.swing.*;
class GUI extends JFrame
{
public static void main (String[] args)
{
GUI gui = new GUI ();
gui.setSize (300, 200);
gui.show ();
}
}
Klasa z metodą main dziedzicząca z klasy JFrame (opisującej
okienko graficzne), która pochodzi z pakietu javax.swing.
Korzysta z najprostszych odziedziczonych metod.
Struktura programu
package ...
// deklaracja pakietu (niekonieczna)
import ...
// deklaracje importu; gdy potrzebne
import ...
/** Komentarz dokumentacyjny
zaczyna się ukośnikiem z dwoma gwiazdkami, kończy gwiazdką i ukośnikiem
*/
// To jest klasa A <- to jest komentarz zwykły
public class A
{
. . .
}
/* To jest
komentarz wielowierszowy
*/
// To jest klasa B
class B {
......
}
Struktura programu - uwagi
Program może być zapisany w jednym lub wielu plikach
źródłowych (.java);
wszystkie
klasy składające się na program można
umieścić w jednym pliku albo każdą klasę można umieścić
w odrębnym pliku;
w jednym pliku .java może się znajdować tylko jedna
klasa publiczna;
jeśli w pliku .java znajduje się klasa publiczna, to plik
musi mieć dokładnie taka samą nazwę, jak ta klasa.
Struktura programu - Aplikacja:
jedna
z klas musi zawierać metodę public static void
main(String[] args),
a.klasa
Przykład:
Work i klasa Inna zdefiniowane w pliku
Work.java
b.po kompilacji dwa pliki: Work.class, Inna.class.
c.Wywołujemy: java Work [argumenty]
Klasy (przypomnienie)
class nazwy klasy
{
Ciało klasy...
}
Przed słowem kluczowym class
wystąpić jeden ze specyfikatorów:
abstract, public, final, lub
dwa z nich:
np. public abstract, public final.
może
Abstract:
klasa abstrakcyjna; nie można utworzyć
instancji (obiektu) tej klasy;
final:
klasa nie może mieć podklas, nie mozna po
niej dziedziczyć;
Brak specyfikatora:
klasa dostępna tylko dla danego pakietu;
Po nazwie klasy mogą wystąpić frazy:
a) ‘extends nazwa_superklasy’
b) ‘implements nazwy_interfejsów’.
a) klasa dziedziczy publicznie (zawsze) od
jednej klasy superklasa.
b) w danej klasie zostaną zdefiniowane
metody, zadeklarowane w
implementowanych interfejsach.
W języku Java każda klasa dziedziczy od
predefiniowanej klasy Object.
Zatem, jeżeli w definicji klasy nie występuje
fraza extends, to jest to równoważne
niejawnemu wystąpieniu w tej definicji frazy
‘extends Object’.
oprócz słowa kluczowego class i nazwy klasy
wszystkie pozostałe elementy w deklaracji klasy są
opcjonalne.
kompilator przyjmie domyślnie, że klasa jest
niepubliczną,
nieabstrakcyjną
i
niefinalną
podklasą predefiniowanej klasy Object.
Przykład
public class Point { int x, ,y; }
równoważne
public class Point { int x, ,y; public Point() { super(); } }
przykład
class Point {int x,y; Point() {x=1; y=2;}}
class CPoint extends Point {
public int color = 0xFF00FF;}
public class Super1 {
public static void main(String args[]){
CPoint cp=new CPoint();
System.out.println("cp.color="+cp.color);
System.out.println("cp.x="+cp.x);
}//end main
}//end Super1
Metody i klasy abstrakcyjne
Metoda abstrakcyjna nie ma implementacji (ciała) i winna być zadeklarowana ze
specyfikatorem abstract.
Klasa, w której zadeklarowano jakąkolwiek metodę abstrakcyjną jest klasą
abstrakcyjną i musi być opatrzona kwalifikatorem abstract.
abstract class SomeClass {
int n;
abstract int getSomething();
void say()
{
System.out.println("Coś tam");
}
}
Abstrakcyjność klasy oznacza, iż nie można bezpośrednio, np. w
wyrażeniu new tworzyć jej egzemplarzy.
Interfejs
interface nazwa {
/* Deklaracje metod i definicje stałych */
}
Interfejsy
Interfejs klasy – jest to wersja klasy pozbawiona pól składowych i definicji metod,
oznacza zestaw metod i zastępuje wielodziedziczenie.
Klasa może implementować wiele interfejsów
Interfejs (deklarowany za pomocą słowa kluczowego interface) to:
•zestaw publicznych abstrakcyjnych metod, (domyślnie – nie trzeba pisać abstract)
•oraz ewentualnie statycznych stałych, (domyślnie – nie trzeba pisać final static)
Implementacja interfejsu w klasie to konieczność
zdefiniowania w tej klasie wszystkich! metod
interfejsu.
Interfejsy
interface Speakable {
int QUIET = 0;
int LOUD = 1;
String getVoice(int voice);
}
interface Moveable {
void startMoving();
void stopMoving();
}
class Pies extends Zwierz implements Speakable, Moveable {
Pies ()
{}
Pies(String s) { super(s); }
String getTyp(){ return "Pies"; }
public String getVoice(int voice) {
if (voice == LOUD) return "HAU... HAU... HAU... ";
else return "hau... hau...";
}
public void startMoving() {
System.out.println("Pies " + name +"biegnie");
}
public void stopMoving() {
System.out.println("Pies " + name +"stanął");
}
}
Pakiety
Przykład 1:
package moj_pakiet;
Przykład 2:
Java.awt.Button b = new Java.awt.Button("0k");
Przykład 3:
import java.awt.Button; // importuje nazwę klasy Java.awt.Button
class A {
java.awt.Frame f = new java.awt.Frame("Tytuł");
Button b = new Button("Ok");
}
Przykład 4:
import java.awt.*; // importuje wszystkie nazwy klas pakietu java.awt
class A {
Frame f = new Frame("Tytuł");// teraz możemy użyć też prostej nazwy klasy
Button b = new Button("0k");// teraz możemy użyć też prostej nazwy klasy
}
Pakiet java.lang nie wymaga importu (m.in. zawiera klasy String i System).
Definiowanie klas
•Dane są reprezentowane przez pola klasy
•Operacje wprowadzamy poprzez definicje metod klasy.
•Zestaw metod klasy nazywany jest jej interfejsem.
•W Javie argumenty przekazywane są metodom wyłącznie przez wartość.
void incr(int x)
{
++x;
}
void przestawPary(Para
pl, Para p2) {
Para temp = pl;
pl = p2;
p2 = temp;
}
Konstruktory – można przeciążać, istnieje konstruktor domyślny dopóki nie
zdefiniujemy własnego
class Para {
int a, b;
Para(int x, int y) {
a = x;
b = y;
}
}
class Para {
int a, b;
Para(int x) {
a = x;
b = x;
}
}
Komunikacja z obiektami
Przykład 1:
TypObiektu identyfikator = new NazwaKlasy(argumenty);
Przykład 2:
TypObiektu identyfikator;
identyfikator = new NazwaKlasy(argumenty);
Para x = new Para(1,3); // Tworzy obiekt klasy Para
// za pomocą konstruktora Para(int, int)
Przykład 3:
Para pl = new
// utworzenie
Para p2 = new
// utworzenie
Para(l,2);
nowego obiektu typu Para, pl - referencja do niego
Para(3,4);
nowego obiektu typu Para, p2 - referencja do niego
Przykład 4:
void add(Para p) {
a = a + p.a ;
b = b + p.b;
}
Słowo kluczowe this
SYTUACJA 1
class Para {
int a;
int b;
void add(int a, int b){
this.a + = a ;
this.b + = b;
}
}
SYTUACJA 2
Para add(Para p)
{
a = a + p.a;
b = b + p. b;
return this;
}
p.add(p1).add(p2).add(
p3);
co jest inną formą zapisu:
p.add(p1);
p.add(p2);
p.add(p3);
SYTUACJA 3:
patrz wywołanie konstruktora z innego konstruktora
Składowe statyczne
Uwaga: Ze statycznych metod nie wolno odwoływać się do niestatycznych
składowych klasy (obiekt może nie istnieć).
Możliwe są natomiast odwołania do innych statycznych składowych.
Przykład: statyczne pole i metoda
class Para{
static int count = 0;
Para(int x, int y)
{
count++;
a = x;
b = y;
}
static void showCount()
{
System.out.println
("Liczba utworzonych par: "+count);
}
}
Para p1 = null,p2 = null;
. . . . . .
if (Para.count == 0)
Para p1 = new Para(1,1);
else
while (Para.count < 10)
{
p2 = new Para(2,2);
p1.add(p2);
}
System.out.println(p1.count);
Para.showCount();
p1.showCount();
p2.showCount();
Typy danych
Typy proste
Nazwa typu
Liczba
bajtów
przedziały wartości
Znaczenie
byte
l
-128...127
short
2
-32768...32767
int
4
-2147483648...2147483647
long
8
-9223372036854775808
...9223372036854775807
float
4
-3.xE+38...3.xE+38
double
8
-1.xE+308...1.xE308
char
2
-0...65556
znaki Unicodu
boolean
1
true false
wartości logiczne:
prawda lub fałsz
liczby całkowite
liczby rzeczywiste
Deklaracje
Deklaracje typów prostych deklaracja jest zarazem
definicją - wydziela w pamięci miejsce na
przechowanie zmiennej danego typu.
Deklaracja zmiennej typu obiektowego jest
faktycznie deklaracją (i definicją) referencji do
obiektu, nie wydziela natomiast w pamięci miejsca
na przechowanie samego obiektu.
String s ;
s = "ala ma kota";
int a = l;
String s = "ala ma kota";
Konwersje arytmetyczne
byte, short, char
float
long
int
double
double.
int ii; short ss;
ss = 1;
ii = ss;
ss = ii; błąd
ss = (short)ii; OK.;
Operatory i wyrażenia
Priorytet, Wiązanie
1, prawe
2, lewe
3, lewe
Operator
Nazwa
!
Negacja logiczna
~
Bitowe uzupełnienie do l
+
Jednoargumentowy + (liczba dodatnia)
-
Jednoargumentowy - (liczba ujemna)
++
Operator zwiększania
--
Operator zmniejszania
(typ)
Konwersja (rzutowanie)
*
Mnożenie
/
Dzielenie
%
Reszta z dzielenia
+
Dodawanie
-
Odejmowanie
Operatory i wyrażenia
Priorytet,
Wiązanie
4, lewe
Operator
Nazwa
<<
Przesunięcie bitowe
>>
Przesunięcie bitowe w prawo
>>>
Przesunięcie bitowe w prawo bez
znaku
<
5, lewe
6, lewe
<=
>=
>
Operatory relacyjne
instanceof
Stwierdzenie typu
==
Operatory równości -
!=
Nierówności
Operatory i wyrażenia
Priorytet, Wiązanie
7,
8.
9,
10,
11,
12, prawe
13, prawe
Operator
Nazwa
&
Bitowa koniunkcja
^
Bitowe wyłączające ALBO
|
Bitowa alternatywa
&&
Logiczna koniunkcja
||
Logiczna alternatywa
?:
Operator warunku
%= += &= |= <<=
Operatory przypisania
Operatory
x = a > b;
x = a > b && c<d;
//x boolean!!!
String s1;
String s2 = "Napis";
s1 = s2 + " tralala";
s1 = s1 + s2;
int k = 1;
s1 = k + k + s2; // 2Napis
s1 = s2 + k + k; // Napis11
s1 = s2 + (k+k); // Napis2
s1 = k + k; // błąd kompilacji (jeden z argumentów musi być typu String)
Operatory
Do porównywania obiektów nie należy używać operatorów
relacyjnych i równości – nierówności!
String s2 = "Napis";
String s3 = new String("Napis");
boolean b;
b = (s2 == s3); // porównanie referencji: wynik false
b = s2.equals(s3); // wynik true.
Instrukcje sterujące
if (wyr) ins
wyrażenie wyr musi być wyrażeniem logicznym.
if (wyr) ins1
else ins2
switch (wyr)
{
case ws1 : ins1
....
case wsN:ins3
default : insDef
}
wyrażenie wyr musi być wyrażeniem całkowitym.
while (wyr) ins;
do ins while (wyr);
for (wyr1; wyr2; wyr3)
ins
continue [etykieta];
break [etykieta];
return wyr;
Instrukcja break
int i = 0;
int j = 0;
outerloop:
// etykieta
while (i < 100)
{
i++;
while(true)
{
j++;
. . . . . .
if (i + j > 10) break outerloop;
// przerwanie pętli oznaczonej etykietą outerloop,
a nie bieżącej
}
}
Zasięg zmiennych
Uwaga: W Javie instrukcje wyrażeniowe i sterujące można umieszczać wyłącznie w
metodach klasy lub w bloku statycznym
Zasięg identyfikatora - fragment programu, w którym może być używany.
Zasięg składowych klasy – w każdym miejscu klasy (miejsce deklaracji nieistotne)
Zasięg identyfikatorów definiowanych wewnątrz metody jest lokalny. Zasięg parametrów
metody jest lokalny
class A {
int a;
void metoda1(){
int b;
}
void metoda2() {
int c;
}
}
W metodzie metoda1() możemy
odwoływać się do zmiennej a,
zmiennej b oraz metody
metoda2(), a w metodzie
metoda2() możemy odwoływać
się do zmiennej a, zmiennej c i
metody metoda1.
Przesłanianie nazw zmiennych
TAK W konstruktorach i metodach możemy przesłaniać identyfikatory pól
klasy:
class A {
int a;
void metoda(){
int a = 0;
// przesłonięcie
a = a + 10;
// zmienna lokalna;
this.a++;
// pole klasy
}
NIE W Javie nie wolno przesłaniać zmiennych lokalnych w blokach
wewnętrznych:
int a;
{
int a;
// BŁĄD kompilacji
}
Czas życia zmiennych
Zmienne lokalne i referencje - od momentu deklaracji do wyjścia sterowania
z bloku
Obiekty – od chwili wykonania operacji new – do chwili usunnięcia przez
garbage collector
class A {
String s ;
void metoda1() {
String pies = new String("Pies");
s = pies;
}
void metoda2(){
System.out.println("Jest " + s);
}
}
Obiekt „pies" został stworzony
w metodzie1.
Referencja pies po zakończeniu
działania tej metody przestaje
istnieć. Ponieważ jednak
referencja s wskazuje na obiekt
„pies”, to obiekt nadal istnieje.
Możemy się do niego odwołać
w metodzie2.
Specyfikatory dostępu
Dostęp do pól i metod klasy
specyfikator dostępu Opis
pola/metody
prywatny
private
dostępna tylko w danej klasie
zaprzyjaźniony / pakietowy
- (ew package)
dostępna ze wszystkich
danego pakietu
chroniony
protected
dostępna z danej klasy i wszystkich
klas ją dziedziczących
publiczny
public
dostępna zewsząd
klas
Inicjalizacja pól
Przy tworzeniu obiektu pola klasy mają zagwarantowaną
inicjalizację na wartości ZERO (0, false - dla typu boolean, null
- dla typów obiektowych,
nie dotyczy to lokalnych zmiennych.
PRZYKŁAD JAWNEJ INICJALIZACJI
class Para {
static String text = "Pary";
static int x = -1;
int a = x+1;
int b = x+1;
Para() { a++; b++; }
static String getText()
{ return text; }
void show(){
System.out.println("( " + a + "," + b + ")");
}
}
Kolejność inicjalizacji pól
REGUŁY DOTYCZĄCE KOLEJNOŚCI:
• każde odwołanie do klasy inicjalizuje najpierw pola statyczne
• tworzenie obiektu (new) inicjalizuje pola niestatyczne, po czym wykonywany jest
konstruktor
• kolejność inicjalizacji pól - według ich kolejności w definicji klasy (w podziale na
statyczne i niestatyczne, najpierw statyczne)
TAK
class Para{
static String text = "Pary";
int a = x+1;
int b = x+1;
Para() { ... }
Para(int x){ ... }
Para(int x, int y) { ... }
static int x = -1;
}
NIE (błąd: forward reference)
class Para {
static int y = x + 1;
int a = x+1;
int b = x+1;
static int x = - 1;
}
Typ tablicowy
Deklaracja tablicy tworzy referencję.
Taka deklaracja nie alokuje pamięci dla samej tablicy.
int[] arr; // arr jest referencją Można pisać też int arr[];
// arr jest zmienną typu int[], który jest typem obiektowym
Alokowanie pamięci. Rozmiar tablicy może być ustalany
dynamicznie podczas działania programu
arr = new int[l0];
int[] tab = new int[n];
Tablice - przykłady
Przykład: Przetwarzanie wszystkich elementów tablicy
public static void main(String[] args)
{
for (int i = 0; i < args.length; i++)
System.out.println(args[i]);
}
Przykład: Przekroczenie zakresu tablicy
– kontrolowanie ilości parametrów programu
public static void main(String[] args){
try{
System.out.println(args[0] + " " + args[1]);}
catch(IndexOutOfBoundsException e){
System.out.println("Syntax: ... ");
System.exit(1);}
}
Tablice - przykłady
Tablice elementów obiektowych – wymaga inicjalizacji wszystkich obiektów - elementów
=
Button[] tab
new Button[n];
for (int i = 0; 1 < tab.length; i++)
tab[i]
=
new Button("Przycisk " + i);
Inicjalizatory klamrowe
int a[] ={1, 2, 3, 4, 5, 3}; //ale tylko w wierszu deklaracji tablicy
Button b[] ={ new Button("A"), new Button("B") , new Button("C"),
/* tu przecinek dozwolony*/ };
Tablice - w przypisaniach
byte[] b1 = {l, 2, 3 };
byte[] b2 = {l, 2, 3, 5, 5 };
b2 = b1;
Tablice - przykłady
Tablice jako argumenty metod
void chgtab(byte[] t){
for( int i=0; i < t.length; i++) t[i]++;
}
byte[] b1 = {1, 2, 3 };
chgtab(b1);
Tablice różnych obiektów (takie tablice także jako argument funkcji)
Component[] tab=new Component[]{new Button("A"),
new Button("B"), new Label("A"), new Label("B"),};
for(int i=0;i<tab.length;i++)
tab[i].setBackground(Color.blue);
Tablice wielowymiarowe
Przykładowe sposoby deklaracji i inicjalizacji:
1. inicjalizacja w nawiasach klamrowych
int[][] macierz1 = {{ l, 2, 3 }, { 4, 5, 6}};
2. dynamicznie
int[][] macierz2 = new int[n][m];
Tablice wielowymiarowe
Przykładowe sposoby deklaracji i inicjalizacji:
3. tablica składa się z wektorów o różnych rozmiarach
public static void main(String[] arg)
{
int w[] = { 2, 3, 4 };
int n = 3;
int[][] m3 = new int[n][];
// rozmiary wierszy będą zm. Dynam.
for(int i = 0; i < m3.length; i++){
m3[i] = new int[w[1]];
for (int j = 0; j < m3[i].
m3[i].length
length; j++)
=
m3[i][j]
i + j;
}
for (int i = 0; i < m3.length; i++) {
System.out.println("Rozmiar i-go wiersza " + m3[i].length);
String out = " ";
for(int j = 0; j < m3[i].length; j++)
out += " " + m3[i][j];
System.out.println(out);
}
}
Przeciążanie metod
void add(Para p)
{ a += p.a; b += p.b;}
void add(int i)
{ a += i; b += i; }
void add(int i, int k){a += i; b += k; }
p.add(jakasPara);
p.add(3);
p.add(1,2);
Przeciążenie konstruktorów
Para(int x) { a = x; b = x; }
// oba pola inicjalizowane tą samą liczbą
Para(int x, int y)
{
// każde pole inicja1izowane inną liczbą
a = x;
b = y;
}
Para() { this(1); }
Para(int x) {this(x,x);}
Para(int x, int y)
{
a = x;
b = y;
}
Dziedziczenie
Sekwencja budowania obiektu klasy pochodnej
1.
2.
3.
4.
wywoływany jest konstruktor klasy pochodnej
jeśli pierwszą instrukcją jest super(args), wykonywany jest konstruktor klasy
bazowej z argumentami args,
jeśli nie ma super(...), wykonywany jest konstruktor bezparametrowy klasy
bazowej,
wykonywane są instrukcje wywołanego konstruktora klasy pochodnej.
Uwaga: Java nie uwzględnia wielodziedziczenia
Podstawowe różnice między kompozycją a dziedziczeniem:
•dziedziczenie pozwala wykorzystywać istniejący interfejs na rzecz obiektu klasy
pochodnej, kompozycja - nie,
•dziedziczenie oznacza, że obiekt klasy pochodnej może być traktowany tak samo jak
obiekt typu definiowanego przez nadklasę.
Obiektowe konwersje rozszerzające
Każdy obiekt możemy przekształcić w obiekt jego (dowolnej) nadklasy.
Nazywa się to konwersją rozszerzającą (rzutowaniem w górę) - upcasting,
(up - bo w górę hierarchii dziedziczenia).
Obiektowe rzutowanie w górę dokonywane jest automatycznie
(nie musimy stosować operatora konwersji) przy:
• przypisywaniu zmiennej-referencji odniesienia do obiektu klasy pochodnej,
• przekazywaniu argumentów, gdy parametr jest typu nadklasy argumentu,
• zwrocie wyniku, gdy wynik podstawiamy na zmienną oznaczającą obiekt nadklasy
zwracanego wyniku.
Obiektowe konwersje rozszerzające
static Para sum(Para pl, Para p2, Para p3)
{
Para p = new Para(0,0);
p.add(pl);
p.add(p2);
p.add(p3);
return p;
}
Para
p1 = new Para(1,2);
ParaInh pi1 = new ParaInh(3,4),
pi2 = new ParaInh(5,6);
Para wynik = sum(pp1, pi1, pi2);
Zastosowanie polimorfizmu
class Zwierz {
String name = "nieznany";
Zwierz() {}
Zwierz(String s) {name = s; }
String getTyp() {return "Jakiś zwierz";}
String getName() {return name;}
String getVoice(){return "?";}
void speak() {
System.out.println(
getTyp()+" "+getName()+" mówi "
+getVoice());
}
}
class Pies extends Zwierz {
Pies(){}
Pies(String s)
{ super(s); }
String getTyp()
{ return "Pies"; }
String getVoice()
{ return "HAU, HAU!"; }
}
class Kot extends Zwierz {
Kot()
{}
Kot(String s)
{ super(s); }
String getTyp()
{ return "Kot"; }
String getVoice()
{ return "Miauuuu..."; }
}
Zastosowanie polimorfizmu
class Main {
public static void main(String[] arg) {
Zwierz z1 = new Zwierz(), z2 = new Zwierz();
Pies pies = new Pies(), kuba = new Pies("Kuba");
Pies reksio = new Pies("Reksio");
Kot kot = new Kot();
Dialog(z1, z2);
Dialog(kuba, reksio);
Dialog(kuba, kot);
Dialog(reksio, pies);
}
static void Dialog(Zwierz z1, Zwierz z2){
z1.speak();
z2.speak();
System.out.println("---------------");
}
}
Wynikiem działania programu będzie następujący wydruk
Jakiś zwierz nieznany mówi ? Jakiś zwierz nieznany mówi ?
Pies Kuba mówi HAU, HAU! Pies Reksio mówi HAU, HAU!
Pies Kuba mówi HAU, HAU! Kot nieznany mówi Miauuuu...
Pies Reksio mówi HAU, HAU! Pies nieznany mówi HAU, HAU!
Metody wirtualne
Wszystkie metody w Javie są wirtualne
za wyjątkiem:
• metod statycznych,
• metod deklarowanych ze specyfikatorem final,
• metod prywatnych (dla których odwołania w innych
metodach danej klasy nie są polimorficzne).
Dynamic binding (Late binding) – mechanizm pozwalający wykryć
na jaki obiekt wskazuje referencja i zastosować odpowiednią metodę.