prosba wyjasnienie polimorfizm Java

0

Witam, mam pytanie - czytam sobie "Thinking in Java 4th ed." i natrafilem na taki kod:

import java.util.*; 

abstract class Shape { 
 void draw() { System.out.println(this + ".draw()"); } 
 abstract public String toString(); 
} 

class Circle extends Shape { 
 public String toString() { return "Circle"; } 
} 

class Square extends Shape { 
 public String toString() { return "Square"; } 
}

class Triangle extends Shape { 
 public String toString() { return "Triangle"; } 
}

public class Shapes { 
 public static void main(String[] args) { 
  List<Shape> shapeList = Arrays.asList( 
   new Circle(), new Square(), new Triangle() 
  ); 
  for(Shape shape : shapeList) 
   shape.draw(); 
 } 
} /* Output: 
Circle.draw() 
Square.draw() 
Triangle.draw() 

Moglby ktos wyjasnic krok po kroku co tu sie dzieje (biorac pod uwage, ze dopiero zaczynam nauke programowania)? Wyjasnienia z ksiazki jakos nie chwytam :/

0
abstract class Shape { 
 void draw() { System.out.println(this + ".draw()"); } 
 abstract public String toString(); 
} 

To abstrakcyjna klasa bazowa - ogólna/podstawowa, umożliwiająca dalsze rozszerzanie, która posiada abstrakcyjną metodę (taka, który musi zostać zaimplementowana w klasie pochodnej). Nie da się utworzyć jej bezpośredniego typu. Metoda draw() jest dziedziczona przez wszystkie pozostałe klasy. Jeśli, któraś klasa będzie chciała zmienić zawartość tej metody musi posłużyć się polimorfizmem - czyli nadpisać tą metodę. W przeciwnym razie zawsze będzie wyświetlana zawartość zdefiniowana w klasie Shape. Abstrakcyjna metoda toString() musi zostać zdefiniowana w każdej klasie pochodnej.

class Circle extends Shape { 
 public String toString() { return "Circle"; } 
} 

Ta klasa, jak i pozostałe dziedziczące po Shape, to klasy konkretne. Tu akurat koło jest typem figury, zatem zachodzi relacja "is-a". Każda taka klasa musi definiować swoją metodę toString().

W klasie Shapes tworzona jest lista figur. Dlaczego lista shapeList jest typu Shape? Dlatego, że interfejs Shape jest typem ogólnym wszystkich pozostałych klas, dlatego do tej listy można dodawać każdy inny typ, który dziedziczy po klasie Shape.
Na końcu wywoływana jest metoda draw() dla każdej klasy.

0

Ok, dzieki za wyjasnienie tego. Mam jeszcze pare pytan, jesli mozna:

  1. czy uzycie akurat tej metody - toString() - ma jakies specjalne znaczenie czy tez moglaby byc uzywa dowolnie nazwana metoda z taka sama implementacja?
  2. wszystkie podklasy maja metode draw(), wiec uzycie slowa kluczowego this powoduje wypisanie nazw klas w wyjsciu? czy gdyby uzyc zamiast this slowa kluczowego super, wszyskie podklasy wypisalyby to samo (tzn Shape.draw())?
  3. czy skoro shapeList jest typu Shape, to obiekty "pochodne" sa upcastowane do tego typu przy inicjalizacji listy? Jesli tak, to w ktorym momencie sa downcastowane?
0

Fakt, drugiego nie musialem, ale nie mam pojecia jak sprawdzic "w praktyce" jakie jest znaczenie takiej nazwy (jesli jakiekolwiek), albo jak sprawdzic w ktorym momencie jest wykonywany upcast (jesli jest w ogole), a potem downcast (jak wczesniej).
_13th_Dragon: Twoj post za to wnosi zupelnie nic.

0

Jeżeli wykonywana jest niejawna konwersja obiektu jakiejś klasy na String to wywoływana jest właśnie metoda toString()

System.out.println(obiekt) <==> System.out.println(obiekt.toString())
"oto obiekt: "+obiekt <==> "oto obiekt: "+obiekt.toString()

Jeśli nie napiszesz metody toString(), to wykorzystana zostanie metoda odziedziczona z klasy Object, ona wypisuje coś takiego: nazwaKlasy@rererencjaDoObiektu.

0
class B
{
    public String m1()
    {
        return "B";
    }
}
class P extends B
{
    public String m1()
    {
        return "P";
    }

    public String m2()
    {
        return "P m2";
    }
}
...
ArrayList<B> lista = new ArrayList<B>();
lista.add(new P());

Dla kompilatora jedyny element listy list: lista.get(0) jest typu B, wywołanie lista.get(0).m2() jest niedopuszczalne. Natomiast każdy obiekt przechowuje informacje o swoim rzeczywistym typie, a nie o typie kolekcji w której został umieszczony.

System.out.println(lista.get(0).getClass()); => class P
System.out.println(lista.get(0).m1()); => P
System.out.println(((P)lista.get(0)).m2()); => P m2
0

Dzieki, to brzmi sensownie, mysle, ze juz rozumiem. Jest jeszcze cos - Eclipse twierdzi, ze mam blad w:
List<Shape> shapeList = Arrays.asList(new Circle()); - Type mismatch: cannot convert from List<Circle> to List<Shape>

Gdy dodam drugi obiekt do listy
List<Shape> shapeList = Arrays.asList(new Circle(), new Triangle());
problem znika. Czemu tak sie dzieje?

1 użytkowników online, w tym zalogowanych: 0, gości: 1