Dziedziczenie i polimorfizm¶
Dziedziczenie i polimorfizm to podstawowe mechanizmy programowania obiektowego. Przykłady i ćwiczenia z tego działu mają na celu zapoznanie ze składnią i koncepcjami stojącymi za dziedziczeniem i polimorfizmem. Wykorzystamy także nabyte umiejętności do zaprojektowania i zaimplementowania prostego przykładu, Twojego własnego pomysłu, wykorzystującego mechanizmy programowania obiektowego.
Przykład 3.1¶
Poniżej znajdziesz kod źródłowy klasy Prostokat, która dziedziczy po bibliotecznej klasie java.awt.Rectangle. Zapoznaj się z dokumentacją klasy java.awt.Rectangle i w oparciu o informacje z wykładu zidentyfikuj elementy składowe które klasa Prostokat odziedziczy po java.awt.Rectangle. Odpowiedz na pytanie co one reprezentują i/lub do czego służą.
import java.awt.Rectangle;
class Prostokat extends Rectangle
{
Prostokat(int a,int b)
{
super(a,b);
}
void info()
{
System.out.println(this);
}
}
public class Program
{
public static void main(String[] args)
{
Prostokat a=new Prostokat(3,4);
a.info();
Prostokat b=new Prostokat(2,2);
b.info();
if(a.intersects(b))
{
System.out.println("-- przecinaja sie --\n");
}
else
{
System.out.println("-- NIE przecinaja sie --\n");
}
a.translate(5,3);
a.info();
if(a.intersects(b))
{
System.out.println("-- przecinaja sie --\n");
}
else
{
System.out.println("-- NIE przecinaja sie --\n");
}
}
}
Ćwiczenie 3.1.1¶
Przeanalizuj zawartość metody main() klasy Program. Zidentyfikuj miejsca w których utworzone zostały obiekty typu Prostokat oraz miejsca w których znajdują się wywołania metod na rzecz tych obiektów. Które z tych metod zostały zaimplementowane w klasie Prostokat, a które są odziedziczone po klasie java.awt.Rectangle? W oparciu o informacje zawarte w dokumentacji klasy java.awt.Rectangle odpowiedz na pytanie do czego służy każda z tych metod i w jakim celu została wykorzystana w powyższym przykładzie.
Ćwiczenie 3.1.2¶
Odpowiedz na pytanie czy konstruktory nadklasy są dziedziczone, a także co oznacza super() w wywołaniu konstruktora podklasy. W oparciu o informacje zawarte w dokumentacji klasy java.awt.Rectangle zaimplementuj konstruktor Prostokat(Point wierzcholek,int dlugosc,int szerokosc), gdzie wierzcholek będzie obiektem klasy java.awt.Point. Skompiluj i przetestuj przykład.
Ćwiczenie 3.1.3¶
W oparciu o informacje zawarte w dokumentacji klasy java.awt.Rectangle zaimplementuj w klasie Prostokat metodę sprawdzającą czy dany prostokąt przylega do innego prostokąta. Skompiluj i przetestuj przykład.
Przykład 2¶
Poniżej znajdziesz prosty przykład ilustrujący koncepcję i wykorzystanie polimorfizmu. Przykład składa się z abstrakcyjnej klasy bazowej Figura i kilku klas konkretnych zawierających implementacje metod obliczających pola i obwody figur geometrycznych.
abstract class Figura //nie mozna tworzyc instancji tej klasy
{
abstract double pole(); //metoda abstrakcyjna
abstract double obwod();
void info()
{
System.out.println(this);
}
}
class Okrag extends Figura
{
double promien;
Okrag(double promien)
{
this.promien=promien;
}
double pole()
{
return 3.14*promien*promien;
}
double obwod()
{
return 2*3.14*promien;
}
public String toString()
{
return "okrag o pr. "+promien;
}
}
class Prostokat extends Figura
{
double dlugosc;
double szerokosc;
Prostokat(double dlugosc,double szerokosc)
{
this.dlugosc=dlugosc;
this.szerokosc=szerokosc;
}
double pole()
{
return dlugosc*szerokosc;
}
double obwod()
{
return 2*dlugosc+2*szerokosc;
}
public String toString()
{
return "prostokat o wym. "+dlugosc+" na "+szerokosc;
}
}
public class Program
{
public static void main(String[] args)
{
Figura z=new Okrag(2);
z.info();
Figura[] a={new Prostokat(3,5),new Okrag(8),new Okrag(3)};
Figura x;
double suma=0;
for(int i=0;i<a.length;i++)
{
x=a[i];
x.info();
suma=suma+x.pole();
}
System.out.println("suma pol figur: "+suma);
}
}
Ćwiczenie 3.2.1¶
Rozwiń powyższy przykład dodając klasy reprezentujące kilka innych figur geometrycznych. Zaimplementuj odpowiednie metody pozwalające na obliczanie pól i obwodów tych figur.
Przykład 3¶
Poniżej znajdziesz szkielet modelu bazy danych dokumentów, która ilustruje mechanizm wykorzystania interfejsów. Warto pamiętać że w języku Java klasy mogą implementować kilka interfejsów, inaczej niż w przypadku dziedziczenia.
class Osoba
{
}
interface Przeszukiwalne
{
boolean czyPasuje(String wzorzec);
}
abstract class Dokument implements Przeszukiwalne
{
}
class Paszport extends Dokument
{
public boolean czyPasuje(String wzorzec)
{
return false;
}
public String toString()
{
return "";
}
}
class DowodOsobisty extends Dokument
{
public boolean czyPasuje(String wzorzec)
{
return false;
}
public String toString()
{
return "";
}
}
public class Program
{
public static void main(String[] args)
{
Dokument[] bazaDanych={new Paszport(),new DowodOsobisty(),new Paszport()};
Dokument z;
String wzorzec="Gorniak";
for(int i=0;i<bazaDanych.length;i++)
{
z=bazaDanych[i];
if(z.czyPasuje(wzorzec))System.out.println("znaleziono: "+z);
}
}
}
Ćwiczenie 3.3.1¶
Rozwiń powyższy przykład. Dodaj odpowiednie pola i zaimplementuj odpowiednie metody, żeby uzyskać model bazy danych dokumentów, realizujący wyszukiwanie według podanego wzorca. Uwaga: porównanie zawartości dwóch obiektów typu String można zrealizować np. za pomocą wywołania funkcji equalsIgnoreCase(String anotherString) z klasy java.lang.String.
Przykład 4¶
Poniżej znajdziesz przykład ilustrujący serializację obiektów do strumienia danych z wykorzystaniem interfejsu Serializable wchodzącego w skład Java Platform API.
import java.io.*;
class Osoba implements Serializable
{
String imie;
String nazwisko;
int rokUrodzenia;
Osoba(String imie,String nazwisko,int rokUrodzenia)
{
this.imie=imie;
this.nazwisko=nazwisko;
this.rokUrodzenia=rokUrodzenia;
}
Osoba(BufferedReader br)
{
try
{
System.out.print("imie: ");
this.imie=br.readLine();
System.out.print("nazwisko: ");
this.nazwisko=br.readLine();
System.out.print("rok urodzenia: ");
this.rokUrodzenia=Integer.parseInt(br.readLine());
}
catch(IOException e){}
}
public String toString()
{
return this.imie+" "+this.nazwisko+" "+this.rokUrodzenia;
}
}
class DowodOsobisty implements Serializable
{
Osoba posiadacz;
String numer;
DowodOsobisty(BufferedReader br)
{
try
{
this.posiadacz=new Osoba(br);
System.out.print("numer do: ");
this.numer=br.readLine();
}
catch(IOException e){}
}
public String toString()
{
return "<do:> "+posiadacz.toString()+" "+this.numer;
}
void info()
{
System.out.println(this);
}
}
public class Program
{
public static void main(String[] args)
{
System.out.println("-- do zapisu --");
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
DowodOsobisty z=new DowodOsobisty(br);
z.info();
try
{
ObjectOutputStream outp=new ObjectOutputStream(new
FileOutputStream("plik.dat"));
outp.writeObject(z);
outp.close();
}
catch(Exception e){System.out.println(e);}
System.out.println("\n-- z pliku --");
ObjectInputStream inp;
try
{
inp=new ObjectInputStream(new FileInputStream("plik.dat"));
Object o=inp.readObject();
DowodOsobisty x=(DowodOsobisty)o;
inp.close();
x.info();
}
catch(Exception e){System.out.println(e);}
}
}
Ćwiczenie 3.4.1¶
Rozwiń powyższy przykład. Zidentyfikuj i obsłuż wyjątek mający miejsce w sytuacji kiedy nie można otworzyć pliku o podanej nazwie.