[Java] polymorfisme

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Bv202
  • Registratie: Oktober 2006
  • Laatst online: 14-11-2021
Hey,

Ik ben bezig dit boek te lezen: http://www.headfirstlabs.com/books/hfooad/

Op een gegeven moment wordt er gebruik gemaakt van polymorfisme op een manier die ik niet snap. Dit is de code, iets simpeler gemaakt:

inventory.java
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Inventory {

  private List inventory;

  public Inventory() {
    inventory = new LinkedList();
  }

  public void addInstrument() {
    Instrument instrument =  new Guitar();
    inventory.add(instrument);

  }

  public Instrument get() {
    for (Iterator i = inventory.iterator(); i.hasNext(); ) {
      Instrument instrument = (Instrument)i.next();
     // code even wat simpeler gemaakt hier. Niet echt logische code nu, maar dat maakt niet uit =P
     return instrument;
  }

}


instrument.java
Java:
1
2
3
4
5
6
7
8
9
10
public abstract class Instrument {
 

  private double price;
  
public Instrument() {
   price = 5.0;
}
 
}


Dan heb je nog een class Guitar die overerft van Instrument.

Nu is de Instrument class dus abstract zodat je geen objecten hiervan kunt aanmaken, maar enkel van de subclasses van Instrument (zoals Guitar).

Dit stuk code snap ik echter niet:
Java:
1
2
3
4
5
6
7
public Instrument get() {
    for (Iterator i = inventory.iterator(); i.hasNext(); ) {
      
      Instrument instrument = (Instrument)i.next(); // deze regel snap ik niet
    
     return instrument;
  }


Hier wordt het object gecast naar een Instrument en zo returned. Maar hoe is dit mogelijk? Instrument is abstract, hoe komt het dat je er dan naar kunt casten? Nu bevat de instrument reference (variabele) een Instrument object, terwijl dit niet mogelijk zou mogen zijn.

De code werkt gewoon, dus is er iets wat ik niet goed snap. Hoe komt het dat dit mogelijk is?

Bedankt :)

Acties:
  • 0 Henk 'm!

  • Amras
  • Registratie: Januari 2003
  • Laatst online: 26-06 19:55
Je kunt een subtype altijd toekennen aan een variabele van zijn supertype. Dit mag dus ook:

Java:
1
2
3
4
5
Instrument guitar = new Guitar(); // Instrument is supertype van Guitar

// Maar dit bijv. ook:

Object o = new Guitar(); // Object is supertype van Guitar


Ik zie dat je dit in eerdere regels ook al gebruikt. Het casten van object naar Instrument verandert daar niets aan.

Java:
1
Instrument instrument = (Instrument)obj;

Bovenstaande mag dus prima, alleen zal dit @runtime een ClassCastException gooien als obj geen subtype van Instrument is.

[ Voor 35% gewijzigd door Amras op 04-08-2010 13:33 ]


Acties:
  • 0 Henk 'm!

  • qanar
  • Registratie: Februari 2008
  • Laatst online: 21-05-2019
Doordat Instrument abstract is kan je geen constructor hebben op deze klasse. Echter een Guitar is ook een Instrument. Dus na
Java:
1
Instrument instrument = (Instrument)i.next();
bevat de variable instrument een Guitar, maar van deze Guitar zijn alleen de functies beschreven op Instrument beschikbaar. De variable Instrument zal echter wel de functies zoals beschreven op het niveau van Guitar uitvoeren en dat is polymorphie :).

http://download-llnw.orac.../java/IandI/abstract.html

Acties:
  • 0 Henk 'm!

  • Bv202
  • Registratie: Oktober 2006
  • Laatst online: 14-11-2021
Hey,

Yup, dat snap ik, maar dat wordt hier niet gedaan:
Instrument instrument = (Instrument)i.next();

Hier wordt het object speciaal gecast naar een Instrument, terwijl die class abstract is :s

EDIT:
bevat de variable instrument een Guitar
Maar waarom? Wordt er niet gecast naar een Instrument ipv een Guitar? (Instrument)i.next()

[ Voor 28% gewijzigd door Bv202 op 04-08-2010 13:33 ]


Acties:
  • 0 Henk 'm!

  • Amras
  • Registratie: Januari 2003
  • Laatst online: 26-06 19:55
Bv202 schreef op woensdag 04 augustus 2010 @ 13:32:
Maar waarom? Wordt er niet gecast naar een Instrument ipv een Guitar? (Instrument)i.next()
Onderwater is het nogsteeds een Guitar. Je kunt hem dus ook weer terugcasten naar een Guitar variabele. :)

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 27-06 12:23

.oisyn

Moderator Devschuur®

Demotivational Speaker

Hier wordt het object speciaal gecast naar een Instrument, terwijl die class abstract is
Nou en? Dat je geen instantie van Instrument kunt maken wil niet zeggen dat je geen referentie naar iets dat Instrument implementeert kan hebben.

Dit kan dus niet
Java:
1
Instrument i = new Instrument();


Maar dit wel:
Java:
1
Instrument i = new Guitar();

[ Voor 22% gewijzigd door .oisyn op 04-08-2010 13:37 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • qanar
  • Registratie: Februari 2008
  • Laatst online: 21-05-2019
Omdat die linked list ook een Violin, Piano of Drum kan bevatten. We zijn alleen zeker dat die LinkedList een Instrumenten bevat. Ik neem aan dat LinkedList.next() een Object returned. Dus moet er nog gecast worden naar een Instrument.

Daarna kan je dan (met bv. instanceof) kijken van welk type je instrument is.

[ Voor 14% gewijzigd door qanar op 04-08-2010 13:37 ]


Acties:
  • 0 Henk 'm!

  • Remus
  • Registratie: Juli 2000
  • Laatst online: 15-08-2021
Bv202 schreef op woensdag 04 augustus 2010 @ 13:32:
Maar waarom? Wordt er niet gecast naar een Instrument ipv een Guitar? (Instrument)i.next()
In dat stuk je maakt het je niet uit wat voor instrument het is, zolang het maar een instrument is. En dat gebruik je meestal omdat je een algemene API (gedefinieerd in een interface of (abstract) class voor een bepaalde type hebt, waarvoor dan verschillende specifieke implementaties zijn. Je bent dan echter alleen geinteresseerd in het gebruik van de API, en niet in de uiteindelijke implementatie (en vaak weet je dat niet eens). Daarom cast je dus naar het type dat de API definieert, in dit geval Instrument.

Overigens is dat code-voorbeeld echt serieus ouderwets, met Generics in java zou dat voorbeeld al een stuk simpeler zijn.

Acties:
  • 0 Henk 'm!

  • Bv202
  • Registratie: Oktober 2006
  • Laatst online: 14-11-2021
Hmmm, ik denk dat ik dit fout begrijp :p

Java:
1
Instrument instrument = (Instrument)i.next();


Wat gaat de referentie instrument nu eigenlijk bevatten? Ik dacht een Instrument instantie, terwijl dit niet mogelijk is.

Acties:
  • 0 Henk 'm!

  • Amras
  • Registratie: Januari 2003
  • Laatst online: 26-06 19:55
Bv202 schreef op woensdag 04 augustus 2010 @ 13:38:
Hmmm, ik denk dat ik dit fout begrijp :p

Java:
1
Instrument instrument = (Instrument)i.next();


Wat gaat de referentie instrument nu eigenlijk bevatten? Ik dacht een Instrument instantie, terwijl dit niet mogelijk is.
Het bevat een subtype van Instrument, omdat Instrument abstract is. Het kan dus een Guitar zijn, of een instantie van iedere andere klasse die van Instrument afleidt. Een instantie maak je aan met een new statement, dus hier wordt geen nieuwe instantie aangemaakt. Hier wordt een bestaande instantie uit de lijst in een Instrument variabele gestopt.

[ Voor 15% gewijzigd door Amras op 04-08-2010 13:43 ]


Acties:
  • 0 Henk 'm!

  • Bv202
  • Registratie: Oktober 2006
  • Laatst online: 14-11-2021
Dus als ik het goed begrijp, zal in dat voorbeeld uiteindelijk een Guitar returned worden (waarvan de referentie een Instrument is)? Of zie ik het nog steeds verkeerd?
Overigens is dat code-voorbeeld echt serieus ouderwets, met Generics in java zou dat voorbeeld al een stuk simpeler zijn.
Hoe zou het dan wel moeten? :p

Acties:
  • 0 Henk 'm!

  • truegrit
  • Registratie: Augustus 2004
  • Laatst online: 25-06 13:44
Dat is wel mogelijk, want een Guitar instantie is ook een Instrument instantie. Het blijft dus een Guitar, maar wordt hier aangegeven als een Instrument.

Vergelijk het met het echte leven. Ik kan een gitaar vasthouden en zeggen: ik heb een instrument in mijn handen. Het is echter een gitaar, die valt onder de categorie instrument. Het is echter niet mogelijk een instrument vast te houden zonder dat het een implementatie is van een instrument, zoals bijvoorbeeld een viool, piano of dwarsfluit.

Dit is praktisch gezien onmogelijk: "Wat voor instrument heb je in je handen? - Geen idee, het is gewoon een instrument"

Zo ook in je gegeven voorbeeld.

Wat je moet snappen is dat een instantie van een object hetzelfde is als de bovenliggende objecten. Dus een Guitar is OOK een Instrument, en OOK een Object. Oftewel, het hele idee van overerven

hallo


Acties:
  • 0 Henk 'm!

  • Jaap-Jan
  • Registratie: Februari 2001
  • Laatst online: 28-06 08:48
Bv202 schreef op woensdag 04 augustus 2010 @ 13:45:
(..)
Hoe zou het dan wel moeten? :p
Java:
1
2
3
4
List<Instument> inventory = new LinkedList<Instrument>(); // Lees: een linkedlist met Instruments
Guitar g = new Guitar();
inventory.add(g);
Instrument i = inventory.get(0); // Geen cast nodig, want de lijst bevat alleen Instruments.

[ Voor 23% gewijzigd door Jaap-Jan op 04-08-2010 13:52 ]

| Last.fm | "Mr Bent liked counting. You could trust numbers, except perhaps for pi, but he was working on that in his spare time and it was bound to give in sooner or later." -Terry Pratchett


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 27-06 12:23

.oisyn

Moderator Devschuur®

Demotivational Speaker

Bv202 schreef op woensdag 04 augustus 2010 @ 13:38:
Hmmm, ik denk dat ik dit fout begrijp :p

Java:
1
Instrument instrument = (Instrument)i.next();


Wat gaat de referentie instrument nu eigenlijk bevatten? Ik dacht een Instrument instantie, terwijl dit niet mogelijk is.
Laat me raden, je hebt C++ geprogrammeerd? :)
De variabele 'instrument' is een referentie. Hij bevat dus een verwijzing naar een object dat Instrument implementeert. Zoals bijv. een Guitar.

[ Voor 16% gewijzigd door .oisyn op 04-08-2010 13:53 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • Bv202
  • Registratie: Oktober 2006
  • Laatst online: 14-11-2021
Hmmm, ik denk dat ik het begin te snappen :p

Dit compiled ook:
Instrument instrument = (Guitar)i.next();

Doet dit dan exact hetzelfde, of niet?

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 27-06 12:23

.oisyn

Moderator Devschuur®

Demotivational Speaker

Min of meer. Jouw code faalt als i.next() eigenlijk een Violin is.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • HMS
  • Registratie: Januari 2004
  • Laatst online: 03:04

HMS

Bv202 schreef op woensdag 04 augustus 2010 @ 14:02:
Hmmm, ik denk dat ik het begin te snappen :p

Dit compiled ook:
Instrument instrument = (Guitar)i.next();

Doet dit dan exact hetzelfde, of niet?
Niet exact, nu ga je er van uit dat de lijst met instrumenten alleen Guitar(s) kan bevatten :). Als het bijvoorbeeld een 'Drum' ofzo is dan krijg je een ClassCastException (Een Drum is geen Guitar, maar wel een Instrument)

Aanname:

Java:
1
2
3
public class Drum extends Instrument { //Niet relevant voor voorbeeld. }

public class Guitar extends Instrument { //Niet relevant voor voorbeeld. }

Acties:
  • 0 Henk 'm!

  • Bv202
  • Registratie: Oktober 2006
  • Laatst online: 14-11-2021
Yup, dat verwachtte ik wel. Ik ging er gewoon even van uit dat enkel er slechts één subklasse van Instrument bestond, hoewel dat natuurlijk geen logisch design is :p

Bedankt voor de reacties, ik snap het nu :)

Acties:
  • 0 Henk 'm!

  • roy-t
  • Registratie: Oktober 2004
  • Laatst online: 27-06 12:22
qanar schreef op woensdag 04 augustus 2010 @ 13:31:
Doordat Instrument abstract is kan je geen constructor hebben op deze klasse. Echter een Guitar is ook een Instrument. Dus na
Java:
1
Instrument instrument = (Instrument)i.next();
bevat de variable instrument een Guitar, maar van deze Guitar zijn alleen de functies beschreven op Instrument beschikbaar. De variable Instrument zal echter wel de functies zoals beschreven op het niveau van Guitar uitvoeren en dat is polymorphie :).

http://download-llnw.orac.../java/IandI/abstract.html
Misschien is dit Java only, maar een abstract class kan wel een constructor hebben in de meeste talen.

Je moet er alleen voor zorgen dat je de constructor aanroept bij het constructen van een subklasse. In java's geval is dat geloof ik door MyBaseObject(..) te doen op de eerste (altijde de eerste) regel van je subclass constructor. (Ja dat is een beetje quircky)

~ Mijn prog blog!


Acties:
  • 0 Henk 'm!

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 21:28

Creepy

Tactical Espionage Splatterer

Ook in Java kan een abstract class een constructor hebben. Voor het aanroepen van de constructor van de baseclass roep je gewoon super() aan vanuit de constructor in de subclass. Dat moet dan wel direct als eerste in de subclass constructor gebeuren.

[ Voor 32% gewijzigd door Creepy op 04-08-2010 15:23 ]

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 27-06 12:23

.oisyn

Moderator Devschuur®

Demotivational Speaker

Je haalt wat dingen door elkaar. Ja, ook abstract classes kunnen natuurlijk gewoon een constructor hebben, dus wat dat betreft zit qanar er falikant naast.

Maar het is niet zo dat omdat het een abstracte class is die een ctor heeft dat je die dan ineens expliciet aan moet roepen. De regel is dat de default ctor standaard wordt aangeroepen. Wil je een andere ctor aanroepen, dan zul je dat handmatig moeten doen in het eerste statement van de ctor van de derived class (en dan met "super", niet met de naam van de base ;))
Java:
1
2
3
4
5
6
7
class Guitar extends Instrument
{
    public Guitar()
    {
        super("Guitar");
    }
}

Maar dat is hier niet relevant, want Instrument heeft alleen maar een default ctor, dus die wordt impliciet aangeroepen.

.edit: 't is niet handig als je wordt gebeld vlak voordat je op post drukt 8)7

[ Voor 5% gewijzigd door .oisyn op 04-08-2010 15:29 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • roy-t
  • Registratie: Oktober 2004
  • Laatst online: 27-06 12:22
Ah ja super() ipv de class naam, ik mix nu C# met Java
(hoewel het in C# via : base() gaat)

~ Mijn prog blog!

Pagina: 1