background image

 
 

Dziedziczenie  

Dziedziczenie  pozwala  na  definiowanie  nowej  klasy  przy  wykorzystaniu  innej  klasy,  już 

wcześniej  zdefiniowanej.  Jeżeli  np.  mamy  zdefiniowaną  już  klasę  Osoba,  a  chcemy  jeszcze 
zdefiniować  klasy  Pracownik  i  Student,  to  nie  musimy  definiować  tych  klas  od  początku,  ale 
wystarczy  napisać,  że  te  nowe  klasy  dziedziczą  po  klasie  Osoba  (bo  posiadają  pewne  wspólne 
pola i metody, np. imię, nazwisko, data urodzenia; metodę wypisującą dane).  

Dziedziczenie  wyraża  się  za  pomocą  słowa  extends.  Jest  ono  zawsze  publiczne.  Nie  ma 

dziedziczenia  wielokrotnego  (tak  jak  w  C++),  czyli  każda  klasa  jest  podklasą  tylko  jednej 
nadklasy. U podstawy hierarchii dziedziczenia znajduje się klasa Object.  

Ogólnie mechanizm dziedziczenia klas można opisać następująco:  

class NazwaNadklasy  
{  
//Definicje pól, metod, zmiennych i funkcji składowych nadklasy  
private Typ1 pole1;  
private Typ2 pole2;  
...  
public NazwaNadklasy(Typ1 pole1, Typ2 pole2) //Konstruktor Nadklasy  
{  
this.pole1 = pole1;  
this.pole2 = pole2;  
}  
...  
}  
class NazwaPodklasy extends NazwaNadklasy  
{  
//Definicje DODATKOWYCH pól, metod, zmiennych i funkcji składowych podklasy  
Typ3 pole3;  
...  
public NazwaPodklasy(Typ1 pole1, Typ2 pole2, Typ3 pole3) //Konstruktor Nadklasy  
{  
super(pole1, pole2); //wywołanie konstruktora nadklasy danej klasy  
this.pole3 = pole3;  
}  
...  
}  

Mamy  tu  zdefiniowaną  nadklasę 

NazwaNadklasy 

oraz  podklasę 

NazwaPodklasy

.  Ponadto 

nadklasą klasy 

NazwaNadklasy 

oraz 

NazwaPodklasy 

jest klasa Object.  

Obiekt  klasy 

NazwaNadklasy 

zawiera  zmienne  opisane  przez  pola 

pole1 

pole2

,  a  także 

konstruktor.  Natomiast  obiekt  klasy 

NazwaPodklasy 

zawiera  takie  same  zmienne  jak  obiekt  klasy 

NazwaNadklasy 

oraz  dodatkowo  zmienną  opisaną  przez  pole 

pole3 

(czyli  zawiera  zmienne 

pole1

pole2 

pole3

), a także własny konstruktor, wywołujący konstruktor nadklasy.  

Przykłąd 

 

Program definiujący klasę Osoba oraz dziedziczącą po niej klasę Pracownik.  

inicja nadklasy Osoba, charakteryzująca pojedynczą osobę  
//Defclass Osoba  
{  
String imie, nazwisko; //Pola klasy Osoba  
int rok_ur;  
//Konstruktor 3-argumentowy, inicjujący pola obiektu klasy Osoba  
Osoba (String imie, String nazwisko, int rok_ur)  
{  
this.imie = imie; //nadanie wartości początkowych polom obiektu klasy Osoba  
...  
}  
//Metoda wypisująca dane obiektu - osoby  
void WypiszDane()  
{  
...  
}  
}  

background image

inicja podkacownik, dziedziczącej po klasie Osoba  
//Deflasy Prclass Pracownik extends Osoba  
{  
String stanowisko; //dodatkowe pola klasy Pracownik  
int staz;  
//Konstruktor 5-argumentowy, inicjujący pola obiektu klasy Pracownik  
Pracownik(String imie, String nazwisko, int rok_ur, String stanowisko, int staz)  
{  
super(imie, nazwisko, rok_ur); //wywołanie konstruktora nadklasy (Osoba), który  
//zainicjuje pola imie, nazwisko i rok_ur  
this.stanowisko = stanowisko; //zainicjowanie pól stanowisko i staz  
...  
}  
//Metoda wypisująca dane obiektu Pracownik  
void WypiszDane()  
{  
System.out.println("Pracownik "+imie+" "+nazwisko+", ur. w roku "+rok_ur+",");  
System.out.println("zatrudniony na stanowisku "+stanowisko+", pracuje lat: "+staz+".\n");  
}  
}  
//Definicja klasy RozneOsoby, zawierającej funkcję główną programu  
public class RozneOsoby  
{  
//Definicja funkcji głównej  
public static void main(String args[])  
{  
//Utworzenie obiektu klasy Pracownik  
Pracownik prac1 = new Pracownik("Jan", "Kowalski", 1961, "wykladowca", 10);  
//Wywołanie metody WypiszDane dla obiektu klasy Pracownik  
prac1.WypiszDane();  
}  
}  

Klasy abstrakcyjne  

Klasa abstrakcyjna jest to klasa, zadeklarowana ze specyfikatorem 

abstract

. Dla takiej klasy nie 

można utworzyć obiektów, ponieważ jest ona definiowana tylko po to, aby  dziedziczyły po niej 
inne  klasy.  Jeżeli  na  danym  stopniu  opisu  ogólnego  możliwych  obiektów  nie  można  podać 
rzeczywistej realizacji (sposobu działania) jednej lub kilku metod, to wtedy nadklasę definiuje się 
jako klasę abstrakcyjną.  

Przykładowo,  jeżeli  w  programie  definiujemy  klasy  opisujące  różne  osoby  (pracowników, 

studentów i in.), to pola i metody wspólne dla różnych osób możemy wyodrębnić w abstrakcyjnej 
nadklasie Osoba. Wtedy, definiując klasę Osoba, możemy pominąć definicję metody wypisującej 
dane osoby, ponieważ dokładne działanie tej metody zależy od typu osoby (np. dla pracowników 
wypisujemy  dodatkowo  stanowisko  i  staż,  a  dla  studentów  –  kierunek,  rok  studiów  i  numer 
indeksu). Dopiero w klasach pochodnych (Pracownik i Student) możemy sprecyzować działanie 
poszczególnych metod wypisujących dane obiektów poszczególnych klas. Dzięki dziedziczeniu z 
klasy  abstrakcyjnej,  wszystkie  rodzaje  osób  opisywane  własnymi  klasami  będą  miały  podobny 
opis ogólny, ułatwiający wymianę informacji.  

Czyli  jeżeli  definicja  klasy  Osoba  będzie  poprzedzona  słowem  kluczowym 

abstract

,  to  nie 

będzie można bezpośrednio utworzyć obiektów klasy Osoba w taki sposób:  

Osoba osoba1 = new Osoba("Jan", "Kowalski", 1990);  

Jeżeli  jakaś  klasa  zawiera  definicję  metody  abstrakcyjnej  (czyli  metody  zadeklarowanej  ze 

specyfikatorem 

abstract

, w której zamiast ciała metody występuje średnik), to musi być jawnie 

zadeklarowana jako abstrakcyjna – czyli nazwę klasy trzeba poprzedzić specyfikatorem 

abstract

Natomiast  w  jednej  z  podklas  klasy  abstrakcyjnej,  dla  każdej  metody  abstrakcyjnej  musi  być 
podana pełna definicja odpowiedniej metody.  

Uwaga!  Jeżeli  podklasa  klasy  abstrakcyjnej  nie  przedefiniuje  wszystkich  metod 

abstrakcyjnych jej nadklasy, to sama staje się klasą abstrakcyjną.  

background image

Program 1  
Program definiujący klasę abstrakcyjną Osoba (zawierającą metodę abstrakcyjną WypiszDane()) 
oraz dziedziczące po niej klasy Pracownik oraz Student.  

/*********************************************************************************************
*  
* Klasę Osoba (charakteryzującą pojedynczą osobę) definiowaliśmy już na poprzednich zajęciach  
**********************************************************************************************
/  
//Definicja ABSTRAKCYJNEJ KLASY Osoba  
abstract class Osoba  
{  
String imie, //Pola klasy Osoba  
nazwisko;  
int rok_ur;  
static int liczba_osob = 0; //Zmienna statyczna, zainicjowana zerem  
//Konstruktor 3-argumentowy, inicjujący pola obiektu klasy Osoba  
Osoba (String imie, String nazwisko, int rok_ur)  
{  
this.imie = imie; //nadanie wartości początkowych polom obiektu  
this.nazwisko = nazwisko;  
this.rok_ur = rok_ur;  
System.out.println("Dziala konstruktor klasy Osoba dla obiektu: "+imie+" "+nazwisko+".");  
liczba_osob++; //uaktualnienie zmiennej statycznej  
}  
//ABSTRAKCYJNA METODA wypisująca dane obiektu  
abstract void WypiszDane();  
//Statyczna funkcja składowa, wypisujące ile obiektów-osób utworzono  
static void IleOsob()  
{  
if (liczba_osob == 0)  
System.out.println("W sytemie nie ma zadnych osob!");  
else  
System.out.println("Liczba osob w systemie: "+liczba_osob+".");  
}  
}  
/****************************************************************************************  
* Dodajemy definicje klas Pracownik i Student, dziedziczących po klasie Osoba  
****************************************************************************************/  
//Definicja klasy Pracownik  
class Pracownik extends Osoba  
{  
String stanowisko; //dodatkowe pola klasy Pracownik  
int staz;  
//Konstruktor 5-argumentowy, inicjujący pola obiektu klasy Pracownik  
Pracownik(String imie, String nazwisko, int rok_ur, String stanowisko, int staz)  
{  
super(imie, nazwisko, rok_ur); //wywołanie konstruktora nadklasy (Osoba), który  
//zainicjuje pola imie, nazwisko i rok_ur  
this.stanowisko = stanowisko; //zainicjowanie pól stanowisko i staz  
this.staz = staz;  
System.out.println("Dziala konstruktor klasy Pracownik dla obiektu: "+imie+" "+nazwisko+".");  
}  
//Pełna definicja metody wypisującej dane dla obiektu Pracownik  
void WypiszDane()  
{  
System.out.println("Pracownik "+imie+" "+nazwisko+", ur. w roku "+rok_ur+",");  
System.out.println("zatrudniony na stanowisku "+stanowisko+", pracuje lat: "+staz+".\n");  
}  
}  
//Definicja klasy Student  
class Student extends Osoba  
{  
String kier; //dodatkowe pola klasy Pracownik  
int rok_stud,  
nr_indeksu;  
//Konstruktor 6-argumentowy, inicjujący pola obiektu klasy Student  
Student(String imie, String nazwisko, int rok_ur, String kier, int rok_stud, int nr_indeksu)  
{  
super(imie, nazwisko, rok_ur); //wywołanie konstruktora nadklasy (Osoba), który  
//zainicjuje pola imie, nazwisko i rok_ur  
this.kier = kier; //zainicjowanie pól kier, rok_stud oraz nr_indeksu  
this.rok_stud = rok_stud;  
this.nr_indeksu = nr_indeksu;  
System.out.println("Dziala konstruktor klasy Student dla obiektu: "+imie+" "+nazwisko+".");  
}  

background image

//Pełna definicja metody wypisującej dane dla obiektu Student  
void WypiszDane()  
{  
System.out.println("Student "+imie+" "+nazwisko+", ur. w roku "+rok_ur+",");  
System.out.print("studiuje na kierunku "+kier+", na roku "+rok_stud);  
System.out.println(", numer indeksu: "+nr_indeksu+".\n");  
}  
}  
/****************************************************************************************  
* Definicja klasy RozneOsobyA, która zawiera funkcję główną programu  
****************************************************************************************/  
//Definicja klasy RozneOsoby  
public class RozneOsobyA  
{  
//Definicja funkcji głównej  
public static void main(String args[])  
{  
Osoba.IleOsob(); //Wywołanie funkcji statycznej składowej klasy Osoba  
//(tu dla klasy Osoba, a nie dla konkretnego obiektu)  
//Utworzenie dwóch obiektów klasy Pracownik  
Pracownik prac1 = new Pracownik("Jan", "Kowalski", 1961, "wykladowca", 10),  
prac2 = new Pracownik("Anna", "Nowak", 1970, "sekretarka", 5);  
//Utworzenie dwóch obiektów klasy Student  
Student stud1 = new Student("Adam", "Kita", 1983, "informatyka", 4, 34332),  
stud2 = new Student("Ada", "Kwiatkowska", 1985, "elektrotechnika", 2, 34338);  
Osoba.IleOsob(); //Wywołanie funkcji statycznej składowej klasy Osoba  
//(można by również napisać np. osoba1.IleOsob())  
//Wywołanie metody WypiszDane dla obiektów klasy Pracownik i Student  
System.out.println("\nPRACOWNICY:");  
prac1.WypiszDane();  
prac2.WypiszDane();  
System.out.println("\nSTUDENCI:");  
stud1.WypiszDane();  
stud2.WypiszDane();  
}  
}  

Interfejsy  
Interfejs (interface) jest to klasa abstrakcyjna, która składa się wyłącznie ze zbioru metod 
abstrakcyjnych oraz ze zbioru statycznych (static) i stałych (final) pól. Kiedy tworzymy nową 
klasę, która wykorzystuje opis metod podanych w danym interfejsie, mówimy, że klasa 
implementuje (implements) dany interfejs, tworząc definicję (realizację) każdej metody 
abstrakcyjnej interfejsu.