Spis treści

Dziedziczenie i polimorfizm

Wprowadzenie

Dziedziczenie i polimorfizm to podstawowe mechanizmy programowania obiektowego. Przykłady i ćwiczenia z tego modułu pozwolą nam zapoznać się ze składnią i koncepcjami stojącymi za dziedziczeniem i polimorfizmem w kontekście języka Java. Wykorzystamy także nabyte umiejętności do zaprojektowania i zaimplementowania prostego przykładu, Twojego własnego pomysłu, wykorzystującego metody programowania obiektowego.

Przykład I

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"); 
      }                                                    
 
   }                                                       
}

ćw. 4.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.

ćw. 4.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.

ćw. 4.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 II

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);               
   }                                                             
}

ćw. 4.4
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 III

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);           
      }                                                                          
   }                                                                             
}

ćw. 4.5
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 IV

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);}                                           
   }                                                                                       
}

ćw. 4.6
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.

ćw. 4.7
Napisz, według własnego pomysłu, program służący do symulacji stanu oszczędności ulokowanych na kilku kontach oszczędnościowych i/lub lokatach bankowych, w kolejnych miesiącach roku. Uwzględnij takie aspekty jak aktualny stan konta, opłata miesięczna za prowadzenie konta, kapitalizacja odsetek oraz tzw. podatek Belki. W tym celu zaimplementuj np. klasę abstrakcyjną „Konto” oraz interfejsy „Oprocentowanie” i „Podatek”, a także klasy reprezentujące konkretne rodzaje kont i lokat bankowych oraz napisz program pozwalający obliczyć stan oszczędności po kilku miesiącach. Zaimplementuj odpowiednie algorytmy obliczania oprocentowania oraz podatku (niezbędne informacje znajdziesz bez trudności w Internecie). Ponieważ do zastosowań finansowych nie należy wykorzystywać arytmetyki zmiennopozycyjnej, do przechowywania stanu konta użyj obiektu klasy bibliotecznej java.math.BigInteger. Alternatywnie, zamiast powyższego przykładu „finansowego”, możesz wykonać inny przykład Twojego pomysłu, pod warunkiem że wykorzystasz w nim mechanizmy dziedziczenia i polimorfizmu.



Z. Dendzik, 2024