[Java, reflection] In static methode een this.getClass() oid

Pagina: 1
Acties:

  • Tuinhark
  • Registratie: April 2000
  • Laatst online: 22-08 20:24
Okee, hier heb ik er eentje voor de collega Java guru's. :)

Situatie:
  • Een abstracte super class (Attribute)
  • Meerdere subclasses van deze class Attribute
Doel:
  • Attribute dient als een factory op te treden. Dus, ipv dat je van de subclasses de constructor gebruikt (die zullen package visible zijn), roept de code een newInstance()-methode aan op Attribute. Deze retourneert vervolgens een nieuwe instantie. Omdat deze newInstance methode wordt overge-erft naar de sub-classes, moet de methode via een this.getClass() achtige constructie achterhalen van welke subclass hij de constructor moet aanroepen. Uiteraard worden alle instanties in een private Vector bijgehouden in de Attribute class, zodat er geen "dubbele instanties" kunnen voorkomen (dwz, meer dan één objecten met zeg-maar dezelfde waarde [er in]).
Probleem:
  • De slimmerikken hadden al opgemerkt dat de methode getClass() niet kan worden gebruikt binnen static methodes. :) En als je gewoon het attribuut class aanspreekt (als in ClassNaam.class), vindt-ie het ook niet goed. Natuurlijk werkt de this referentie ook niet.
Code:
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
public abstract class Attribute {
    private int skill;
    private static final java.util.Vector heap = new java.util.Vector();

    Attribute(int s) {
        skill = s;
    }

    public static final Attribute newInstance(final int skill) throws InstantiationException
    {
        Class skillClass = getClass();  // hier gaat het mis!!
        Attribute element;
        Attribute returnElement = null;

        for (int i = 0; heap != null && i < heap.size() && returnElement == null; i++)
        {
            element = (Attribute)heap.elementAt(i);
            if (element.getSkill() == skill)
                returnElement = element;
        }

        if (returnElement == null)
        {
            try
            {
//System.out.println("NewInstance: " + skillClass.getName() + " (" + skill + ")");
                Constructor skillClassConstructor = skillClass.getConstructor(new Class[]{Integer.TYPE});
                returnElement = (Attribute)skillClassConstructor.newInstance(new Object[]{new Integer(skill)});
                if (heap != null)
                    heap.addElement(returnElement);
            }
            catch (NoSuchMethodException e)
            {
                System.out.println("nsme");
                InstantiationException eNew = new InstantiationException(e.getMessage());
                eNew.setStackTrace(e.getStackTrace());
                throw eNew;
            }
            catch (IllegalAccessException e)
            {
                System.out.println("iae");
                InstantiationException eNew = new InstantiationException(e.getMessage());
                eNew.setStackTrace(e.getStackTrace());
                throw eNew;
            }
            catch (InvocationTargetException e)
            {
                System.out.println("ite");
                InstantiationException eNew = new InstantiationException(e.getMessage());
                eNew.setStackTrace(e.getCause().getStackTrace());
                throw eNew;
            }
        }

        return returnElement;
    }

    public final int getSkill() {
        return skill;
    }
}


Toelichting bij code:
  • De 'waarde' waar ik het hierboven over had is natuurlijk die integer skill. ;)
  • De regel waar het fout gaat is aangegeven.
Wat ik nu dus wil is een java.lang.Class object waarmee ik gewoon weer nieuwe instanties kan maken. Ik heb zo'n donkerpaars vermoeden dat het überhaupt niet gaat lukken, maar misschien dat er hier iemand is die hier nog iets zinnigs over heeft te melden. *D

BVD
:Y)

  • Tuinhark
  • Registratie: April 2000
  • Laatst online: 22-08 20:24
Laat ik bij deze ook de eerste zijn die een mogelijke oplossing aanbrengt... ;)

Het probleem is op te lossen door deze factory constructie te implementeren op alle subclasses... Zo hoeft de methode niet meer te checken op het type class. Alleen is dat natuurlijk niet erg efficiënt.

:Y)

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Allereerst even hulde voor je uitgebreide en verzorgde verhaal ;) .

De oplossing kan je zelf wel voelen aankomen: geen reflectie en scheiding van de factory in een aparte klasse. Ik kan het voor gaan doen, maar wellicht dat je zelf al wel weet in welke richting je dan moet gaan denken?

Klein vraagje: waarom gebruik je geen HashMap om je de attributen op te slaan? Je hoeft dan niet heel de Vector door te lopen...

Ander klein vraagje: je zegt dat je verschillende subklassen kan aanmaken, maar ik begrijp dat je dus per skill maar 1 instantie hebt? Je kan dus niet verschillende instanties hebben voor de subklassen met dezelfde skill?

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

Waarom is dat niet efficient?

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Die exception kan je trouwens beter inpakken: tegenwoordig kan je een exception aanmaken met een andere exception. Dit wordt dan de 'cause' genoemd.

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Kan je trouwens nog iets zeggen over de reden van deze structuur: wat zijn de subklassen en waarom wil je deze subklassen construeren?

Je zou namelijk ook kunnen wegen om al deze klassen gewoon in 1 Factory aan te maken en verschillende methode namen te kiezen voor de verschillende situaties. Het hangt even af van de situatie of dit fraai is, maar ik snap niet echt wat nu eigenlijk je doel is, dus dat is een beetje lastig te beoordelen ;) .

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • Tuinhark
  • Registratie: April 2000
  • Laatst online: 22-08 20:24
mbravenboer: De oplossing kan je zelf wel voelen aankomen: geen reflectie en scheiding van de factory in een aparte klasse. Ik kan het voor gaan doen, maar wellicht dat je zelf al wel weet in welke richting je dan moet gaan denken?
Dat is het hem trouwens: op dit moment gebruik ik al een externe factory, maar het is inmiddels al een hele grote omdat ik voor iedere subclass (en het zijn er al heel wat) een eigen newInstance() methode heb. Beetje hetzelfde idee als eentje op iedere subclass, dus dat zou geen echt verschil uitmaken. ;)
mbravenboer: Klein vraagje: waarom gebruik je geen HashMap om je de attributen op te slaan? Je hoeft dan niet heel de Vector door te lopen...
Dat is een hele goede. :) Op andere plekken gebruik ik dat ook. (Je begrijpt dat dit hele gebeuren slechts een klein radertje is in een veel groter projectje. :+) Ik zal dat nog ff optimaliseren. :)
mbravenboer: Ander klein vraagje: je zegt dat je verschillende subklassen kan aanmaken, maar ik begrijp dat je dus per skill maar 1 instantie hebt? Je kan dus niet verschillende instanties hebben voor de subklassen met dezelfde skill?
Ik zal ff wat toelichten op de situatie. Je hebt dus de abstracte class Attribute. Daaronder heb je (o.a.) de classes Scoring, Passing, Defending, etc, etc. Dat skill wordt gebruikt om aan te geven hoe goed die attributen zijn ontwikkeld (we hebben het trouwens over een 'voetballer' ;)). Omdat bv bij verschillende spelers het attribuut Scoring even sterk is, wil ik dat beide voetballers een referentie naar dezelfde Scoring-instantie wordt bijgehouden. (Ik heb goede redenen om deze class-structuur te gebruiken ipv simpele integers, dus laten we dat even buiten de discussie laten. :))
ACM: Waarom is dat niet efficient?
Sjah, zo heeft Sinnema mij dat niet geleerd. :D Gekkigheid. Het is code voor gemeenschappelijke functionaliteit. Dan is het gewoon een slecht idee om die zelfde code op meerdere 'plekken' te plaatsen. Da's slecht voor de onderhoudbaarheid.
mbravenboer: Die exception kan je trouwens beter inpakken: tegenwoordig kan je een exception aanmaken met een andere exception. Dit wordt dan de 'cause' genoemd.
Ja ik weet, dat doen we nog wel. ;)
mbravenboer: Kan je trouwens nog iets zeggen over de reden van deze structuur: wat zijn de subklassen en waarom wil je deze subklassen construeren?

Je zou namelijk ook kunnen wegen om al deze klassen gewoon in 1 Factory aan te maken en verschillende methode namen te kiezen voor de verschillende situaties. Het hangt even af van de situatie of dit fraai is, maar ik snap niet echt wat nu eigenlijk je doel is, dus dat is een beetje lastig te beoordelen ;) .
Ik denk dat dit inmiddels duidelijk is, niet? :)

edit:

Hej, feli trouwens ACM. (8>


:Y)

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Tuinhark: Beetje hetzelfde idee als eentje op iedere subclass, dus dat zou geen echt verschil uitmaken. ;)
Jawel: als je het scheid in een aparte klasse structuur kan je gebruik maken van overerving, abstracte methoden en nadere OO gedoe. Bij het gebruik van static methoden ontneem je jezelf in feite alle mogelijkheden, zoals je zojuist zelf hebt ondervonden ;) . Je moet daarom over het algemeen even goed nadenken voordat je static methoden gaat gebruiken.

In dit geval moet je bijvoorbeeld het construeren van nieuwe objecten los zien van het cachen van instanties. Dit laatste kan je generiek implementeren, construeren van instanties is per definitie specifiek. Door een klasse structuur te gebruiken voor je factories kan je de constructie in de base-class implementeren en de constructie van specifieke instanties in de subklassen.

Ik begrijp dus trouwens dat je dus slechts per attribuut 1 skill wilt hebben. Op dit moment werkt je oplossing daardoor niet: alle subklassen delen het static field 'heap' in je attribuut klasse.

Voorbeeld:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Test {
  public static void main(String[] ps) {
    Boe.x = 1;

    System.out.println("Bah: " + Bah.x);
  }
}


class Bla {
  public static int x = 0;
}

class Boe extends Bla {
}

class Bah extends Bla {
}


Daarom is er nog meer reden om met gewone klassen en gewone methoden te gaan werken: je kan je cache dan generiek implementeren, maar toch elk attribuut een eigen cache laten hebben.
Sjah, zo heeft Sinnema mij dat niet geleerd. :D Gekkigheid.
Luister nu maar naar ons, dan komt alles goed ;) .

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Ik denk trouwens dat ACM je hier nog wel wat voorbeeld code van kan laten zien :D >:) .

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • Tuinhark
  • Registratie: April 2000
  • Laatst online: 22-08 20:24
Oja? Doe es vertellen? :)

Anyway, ik denk dat je het idee nog niet helemaal snapt.. (of ik begrijp jou natuurlijk niet :)) Das niet erg, ik leg het nog ff opnieuw uit:
  • Je hebt voetballers. Dat zijn instanties van de class Player.
  • Je hebt verschillende soorten attributen (Scoring, Passing, etc) en elke voetballer heeft dezelfde soorten attributen.
  • Wanneer 2 voetballers gelijke sterk zijn in een bepaald opzicht (bv Scoring), hebben deze attributen op beide voetballer-objecten natuurlijk dezelfde waarde.
  • Omdat ik niet met simpele integers werk (om de waarde aan te geven), maar met deze class structuur (Attribute + subclasses), wijzen de Scoring fields in beide spelers-objecten naar dezelfde instantie van de class Scoring. (volgt u nog?)
  • Dit vanuit het oogpunt van efficiëntie en vandaar een factory-oplossing. Deze attribute-objecten zijn toch immutable, dus is het geen probleem.
  • En natuurlijk wilde ik een generieke factory-oplossing omdat er inmiddels HEEL wat verschillende soorten attributen (subclasses van Attribuut) zijn.
  • edit:
    En daarom wilde ik de newInstance()-methode hebben op de gemeenschappelijke superclass, Attribute, wat dus niet werkt. :)
Hehe, eigenlijk moet ik er even een class diagram bij maken ofzo. :P

NB: Er zijn ook al 'attributen' die niet van toepassing zijn op voetballers en binnen een heel andere context worden gebruikt, maar dat ter zijde en verandert niets aan de oorspronkelijke situatie. :)

Oja, dat Sinnema gedoe snapt Alarmnummer geloof ik wel. ;)

:Y)

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Je komt heel goed over, maar ik geloof dat vooral ik te warrig praat ;) . Ik zal even een kleine demo maken...

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • Tuinhark
  • Registratie: April 2000
  • Laatst online: 22-08 20:24
Cool, tnx. Take your time. :)

Ik ga zo :z omdat ik toch redelijkerwijs vroeg op moet (of hoe gaat die uitdrukking ook? B)), dus dan reageer ik later vandaag nog wel weer.

:Y)

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Tis al bijna klaar, het gebruik zelfs nog WeakReferences ook :+ .

Ik maak ff een kleine test nog.

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Allereerst de attributen:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Attribute {
  private int _skill;

  public Attribute(int skill) {
    super();
    _skill = skill;
  }

  public int getSkill() {
    return _skill;
  }
}

public class PassingAttribute extends Attribute {
  public PassingAttribute(int skill) {
    super(skill);
  }
}

public class ScoringAttribute extends Attribute {
  public ScoringAttribute(int skill) {
    super(skill);
  }
}


Lijkt mij niets nieuws :) .

Dan nu de sleutel: de Cache. Ik gebruik hier geparameterizeerde typen, maar dan kan je vervangen door de algemene base klasse Attribute als je daar nog niet helemaal aan toe bent.

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import java.lang.ref.WeakReference;

public class Cache<O extends Attribute> {

  private IntHashtable<WeakReference<O>> _objects;
  public final Object LOCK;

  public Cache() {
    super();
    _objects  = new IntHashtable<WeakReference<O>>();
    LOCK    = new Object();
  }

  public O get(int id, O alternative) {
    O result;

    synchronized(LOCK) {
      result = get(id);
      
      if(result == null) {
        put(alternative);
        result = alternative;
      }
    }

    return result;
  }

  public O get(int id) {
    O result;
    
    if(_objects.containsKey(id)) {
      result = _objects.get(id).get();
    }
    else { 
      result = null;
    }
    
    return result;
  }
  
  public void put(O object) {
    _objects.put(object.getSkill(), new WeakReference<O>(object));
  }
}


Ik gebruik hier ook nog weak references om er zo voor te zorgen dat de objecten in de Cache niet 'meetellen' voor de garbage collector: als er geen andere referentie meer naar is, vallen ze dus weg.

Tot slot maak ik voor elk attribuut en Cache en verzamel dit alles in 1 klasse. Dit kan nog wel compacter, maar dat wordt vrij tricky.
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class AttributeCaches {

  private Cache<PassingAttribute> _passing;
  private Cache<ScoringAttribute> _scoring;

  public AttributeCaches() {
    super();
    _passing = new Cache<PassingAttribute>();
    _scoring = new Cache<ScoringAttribute>();
  }

  public ScoringAttribute getScoring(int skill) {
    ScoringAttribute result = _scoring.get(skill);

    if(result == null) {
      result = new ScoringAttribute(skill);
      _scoring.put(result);
    }

    return result;
  }

  public PassingAttribute getPassing(int skill) {
    PassingAttribute result = _passing.get(skill);

    if(result == null) {
      result = new PassingAttribute(skill);
      _passing.put(result);
    }

    return result;
  }
}


Dan helemaal tot slot ene kleine test applicatie:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
public class Main {

  public static void main(String[] ps) {
    AttributeCaches cache = new AttributeCaches();

    ScoringAttribute att1 = cache.getScoring(3);
    ScoringAttribute att2 = cache.getScoring(4);
    ScoringAttribute att3 = cache.getScoring(4);

    System.out.println("Same? " + (att2 == att3));

  }
}


En het werkt nog ook ;) .

De IntHashtable is een eigen browsels die ervoor zorgt dat je de int primitieve als key kan gebruiken. Als je die wilt hebben moet je maar even roepen, maar je kan ook gewoon de HashMap gebruiken met een Integer.

Zo duidelijk? Of heb ik je toch verkeerd begrepen? ;)

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Hum, de enters vallen weer weg. Je kan de source van m'n bericht bekijken om de versie met enters te zien...

De synchronizatie in de cache hierboven klopt trouwens niet. Het voorbeeld is vlug knip en plak werk van een grotere klasse. Als je synchronizatie nodig hebt mag je zelf bedenken hoe het wel moet ;) .

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • wasigh
  • Registratie: Januari 2001
  • Niet online

wasigh

wasigh.blogspot.com

Je kunt toch ook de classes laden door de hele naam mee te geven?
Of heb ik nu de essentie van de hele discussie gemist?

  • Tuinhark
  • Registratie: April 2000
  • Laatst online: 22-08 20:24
Ik vermoed dat ik je wel volg, maar tevens denk ik dat dat hele generics gebeuren een beetje overkill is.. Misschien ook wel niet trouwens.

Ik heb me in het verleden daar wel eens op gestort en toen ik er achter kwam dat je weer een andere (meegeleverde) compiler moest gebruiken (en ik mijn Jikes compiler aan de kant kon schuiven), hoefde het niet zo nodig meer van mij. ;)

True, het is extreem nuttig om de compiler te kunnen laten type-checken op gebruik van/met Vectors e.d. Maar zo heel nodig heb ik die specifieke functionaliteit nog niet gehad. :)

Ik denk dat ik eerst de externe factory class (waar jouw AttributeCaches eik op neer komt :)) gewoon nog even laat bestaan.

Wasigh: Ja, dat werkt ook, maar where's the fun in that? B)

:Y)

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

*vind generics ook overgewardeerd... net zoals multimethods, exception, oo, hogere orde functies, collection frameworks, krachtig typesysteem etc*

gewoon weer terug naar ASM, al die nieuwerwetse fratsen zijn helemaal nergens goed voor.

[edit]
aha.. Sinnema, rots in de branding, licht in de duisternis, kneder van het onkneedbare ;) Ook op de Hanze gezeten dus :)

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Ik was dus even sarcastisch ;)

Generics zijn erg handig. Het is niet alleen praktisch voor het compile time checken van types van lijsten, maar het bied je de mogelijkheid om niet alleen met polymorphisme code te gaan re-usen.

Je krijgt door geparametriseerde polymorphisme een nieuwe manier aangeboden om code 'in te lassen' in andere objecten en hierdoor kan je echt veel mooiere constructies maken. Op dit moment gebruik ik het standaard en zou echt niet meer zonder willen.

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Geparameterizeerde typen zijn onmisbaar als je plezier in het programmeren in Java/C# wilt hebbem... Alarmnummer heeft het al aardig omschreven en als je nog meer argumenten wilt lezen kan je in de search nog aardig wat vinden :) .

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • Tuinhark
  • Registratie: April 2000
  • Laatst online: 22-08 20:24
Ik zal eens kijken dan. Mijn interesse is iig gewekt. :)

(Op voorhand, voordat ik de search heb bekeken: ) Er vanuit gaande dat jullie allebei gebruik maken van generics, kan ik dan ook aannemen dat jullie met die meegeleverde compiler werken (javac 'alternatief')? Of is er ook een manier om met bv de huidige versie van Jikes het generics gebeuren aan de gang te krijgen?

:Y)

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Je hebt een nieuwe compiler nodig omdat de syntax is gewijzigd. Deze kan je hier krijgen (maar dat had je zelf ook al uit gevonden geloof ik). En ik werk zelf met Nice. Helaas is het geparametriseerde polymorphisme gedeelte nog niet klaar, maar andere features maken de taal vele malen interessanter dan Java.

En waarom verkies je Jikes boven de orginele java compiler? De enigste voordelen zijn de schijnbaar betere (ben ik het niet mee eens) foutmeldingen en de snelheid (waar ik zelf ook geen problemen mee heb)

  • Tuinhark
  • Registratie: April 2000
  • Laatst online: 22-08 20:24
I'll admit: de foutmeldingen van Jikes zijn soms ronduit confusing.. Maar hij is wel extreem snel met compilen. Vooral bij mijn vorige werkgever waar ik aan een redelijk groot Java project werkte, was Jikes een uitkomst (want die machines waren niet vooruit te branden :(). Ik durf Jikes best een factor 5 tot 10 sneller te noemen dan standaard javac.

Vooral ook de -depends switch vindt ik een briljante vinding die javac wat mij betreft zsm kan overnemen. Deze zorgt er voor dat ALLE classes die direct EN indirect worden gereferenced door de te compilen class A worden meegecompiled.

Situatie: Class A gebruikt class B en die gebruikt op zijn beurt weer class C en je gebruikt geen Jikes compiler icm -depends switch. ;)
Je verandert class C en je compiled class A.. Dan compiled hij class C niet mee omdat de compiler niet 'voorbij' class B komt (omdat die niet gewijzigd is) en dus niet ziet dat class C is gewijzigd.

(Sorry voor de vreemde uitleg, maar weet het even niet beter te verwoorden.)

:Y)

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Ik had het geluk dat ik met een zeer handige IDE werkte die oa syntax checking doet. Je hoeft dus nauwelijks meer te compilen.

Op dit moment zit ik dus aan jedit + dospromt en dat bevalt me eerlijk gezegd ook wel. Het is dan wel niet snel (7 seconden voor compilen van 20 a 30 sources + junit testen + dirs verwijderen ed) maar ik kan er wel mee leven.

Verder ben ik op dit moment meer tijd bezig van mijn toetsenbord dan aan mijn toetsenbord omdat ik allerlei nieuwe technieken onder de vingers probeer te krijgen en daarvoor toch wel redelijk achter de boeken moet zitten.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 31-08 15:26

.oisyn

Moderator Devschuur®

Demotivational Speaker

Om even terug te komen op je originele probleem:

Tuinhark schreef op 22 september 2002 @ 00:49:
Probleem:
  • De slimmerikken hadden al opgemerkt dat de methode getClass() niet kan worden gebruikt binnen static methodes. :) En als je gewoon het attribuut class aanspreekt (als in ClassNaam.class), vindt-ie het ook niet goed. Natuurlijk werkt de this referentie ook niet.


Behalve de getClass () methode kun je ook gewoon bij het static attribuut class (wel even je klasse ervoor zetten, anders snapt de parser het niet):
ho niet goed gelezen :)
Je zegt dat dat bij jou niet werkt :? Bij mij compileert het onderstaande prima:

Java:
1
2
3
4
5
6
7
public class Blaat
{
    public static void main (String args[])
    {
        System.out.println (Blaat.class);
    }
}

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.


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Tuinhark: kan ik dan ook aannemen dat jullie met die meegeleverde compiler werken (javac 'alternatief')?
Ik werk met het Generics Prototype, zie mijn signature. Ik heb de zaak opgenomen in Ant zodat ik met vrijwel geen enkele moeite het prototype kan gebruiken voor mijn projecten. Ik vertik het overigens om iets te programmeren zonder Generics :+ .
Of is er ook een manier om met bv de huidige versie van Jikes het generics gebeuren aan de gang te krijgen?
Nee, maar ik denk dat Jikes binnen afzienbare tijd ook aan een generics implementatie gaat werken. Ze zullen wel moeten, want generics staat gepland voor 1.5.

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
.oisyn: Je zegt dat dat bij jou niet werkt :? Bij mij compileert het onderstaande prima
Het probleem is dat de static methode hier aangeroepen werd op een subklasse (niet fraai overigens) en dat hij daarbij wilde weten op welke subklasse deze methode aangeroepen was. Dit krijg je niet voor elkaar met standaard Java, alleen met gesloten reflectie packages van Sun lukt het wel.

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • Tuinhark
  • Registratie: April 2000
  • Laatst online: 22-08 20:24
Okee.. Tijd voor een kick. :)

Niet omdat mijn probleem niet opgelost is, maar omdat ik een new situation heb in dezelfde context. (lees bovenstaand verhaal voor een situatieschets)

Ik heb nu onderstaande code voor de AttributeCache:
(let niet op evt. mogelijke optimalisaties, daar gaat het nu niet om)
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
public class AttributeCache<O extends Attribute> {

    private HashSet<O> _objects;

    public AttributeCache() {
        _objects = new HashSet<O>();
    }

    public synchronized O get(int id) throws NoSuchElementException
    {
        O result = null;

        Iterator<O> iter = _objects.iterator();
        boolean found = false;
        O step = null;
        while (!found && iter.hasNext())
        {
            step = iter.next();
            if (step.getSkill() == id)
                result = step;
        }
        if (result == null)
            throw new NoSuchElementException("not found: " + id);

        return result;
    }

    public synchronized void put(O object)
    {
        if (object == null)
            throw new NullPointerException("null object");

        try {
            get(object.getSkill());
        } catch (NoSuchElementException e) {
            _objects.add(object);
        }
    }

    public synchronized O newInstance(int i) throws InstantiationException
    {
        try
        {
            return get(i);
        }
        catch (NoSuchElementException e)
        {
            try
            {
                Integer key = new Integer(i);
                Class oClass = O.class;
                Constructor oConstr = oClass.getConstructor(new Class[]{Integer.TYPE});

                O newInstance = new Attribute<O>(i);    // compiled niet
                //O newInstance = (O)oConstr.newInstance(new Object[]{key});

                put(newInstance);
                return newInstance;
            }
            catch (InstantiationException e2)
            {
                throw e2;
            }
            catch (InvocationTargetException e2)
            {
                e2.getCause().printStackTrace();
            }
            catch (Exception e2)
            {
                InstantiationException eNew = new InstantiationException(e2.getMessage());
                eNew.setStackTrace(e2.getStackTrace());
                throw eNew;
            }
            throw new AssertionError("misc exc");
        }
    }
}


Naast deze class heb ik nog steeds de class AttributeFactory dat voor iedere subclass van Attribute een instantie van AttributeCache bijhoudt, getypeert op die specifieke subclass. Deze AttributeFactory roept de methode newInstance() aan op de respectievelijke AttributeCache wanneer er een nieuwe instantie moet komen. B)

De bedoeling was nog steeds om het factory proces uit te besteden. ;) Van belang hierbij is de laatste methode in bovenstaande code, waar een nieuwe instantie wordt aangevraagd met de gespecificeerde waarde.

Het aanmaken van een nieuw object middels O newInstance = new O(i); mag niet van de compiler. Daarentegen werkt het volgende niet: O newInstance = (O)oConstr.newInstance(new Object[]{key});. Ik eindig hiermee met (meen ik) instanties van Attribute ipv O (dat toch echt een subclass van Attribute voorstelt, toch? :?)

Zoals jullie kunnen zien ben ook ik inmiddels over op het Generics gebeuren van Java en moet zeggen dat het me absoluut bevalt! 'k Wilde dat ik er eerder van gebruik kon maken (laat maar, laaang verhaal ;)).

Anyway, zijn er hier weer zekere iemanden die hier iets zinnigs over kunnen zeggen. Uiteraard heb ik zelf al bij Google zitten zoeken naar 'java generics new instance' e.d., maar niet iets kunnen vinden dat naar de oplossing leidt.

:Y)

PS: Sorry voor evt. onduidelijkheden/wazigheid.. het is alweer lang bedtijd geweest.. :z Ik zal later vandaag als ik weer bij m'n positieven ben even opnieuw de situatie bekijken en reageren. :7

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Wat jij doet
O newInstance = new Attribute<O>(i);
is de Attribute class parametriseren terwijl dit denk ik niet de bedoeling is. Jij hebt niet de volgende code:

class Attribute<Z extends Attribute>{
}

Jij wilt dus een nieuwe instantie aanmaken op basis van O:
O newInstance = new O(i);
volgens mij moet dit wel werken.

Alhoewel ik wel ernstige twijfels heb over die constructor. Van een subtype weet je in ieder geval welke methodes er zeker in zullen zitten dus die kan je altijd aanroepen. Maar dat kan je dus niet zeggen over Constructors omdat een constructor bij een parent class niet voor hoeft te komen bij een subclass. Dus wie zegt dat iedere subclass van Attribute ook die constructor heeft. Ik zal er even na kijken *is ook nog niet zo lang bezig met generics*

  • Tuinhark
  • Registratie: April 2000
  • Laatst online: 22-08 20:24
Alarmnummer: Wat jij doet
O newInstance = new Attribute<O>(i);
is de Attribute class parametriseren terwijl dit denk ik niet de bedoeling is. Jij hebt niet de volgende code:

class Attribute<Z extends Attribute>{
}

Jij wilt dus een nieuwe instantie aanmaken op basis van O:
O newInstance = new O(i);
volgens mij moet dit wel werken.
Je hebt gelijk.. dat was idd fout. Wat ik oorspronkelijk daar had staan was ook al:
O newInstance = new O(i); :)
Alhoewel ik wel ernstige twijfels heb over die constructor. Van een subtype weet je in ieder geval welke methodes er zeker in zullen zitten dus die kan je altijd aanroepen. Maar dat kan je dus niet zeggen over Constructors omdat een constructor bij een parent class niet voor hoeft te komen bij een subclass. Dus wie zegt dat iedere subclass van Attribute ook die constructor heeft. Ik zal er even na kijken *is ook nog niet zo lang bezig met generics*
En ook hier heb je heb je gelijk. Omdat een constructor niet per definitie onderdeel is van de interface van een class, kan het inderdaad zijn dat een aanroep als bovenstaande niet werkt.

Verder, deze instructie:
O newInstance = (O)oConstr.newInstance(new Object[]{key});
werkt niet omdat ik een InstantiationException krijg. In de API dox staat dat die wordt gegooid wanneer je middels reflection een instantie probeert te maken van een abstract class.

Nader onderzoek wijst inderdaad uit dat O.class == Attribute.class en Attribute was inderdaad de abstracte superclass.

Duss.. there you have it. :D Volgens mij wil ik weer het onmogelijke. :7

:Y)

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Ik wil wel graag weten hoe
O newInstance = new O(i);
gefixed kan worden. Ik denk dat mbravenboer daar wel een oplossing voor weet.

  • Tuinhark
  • Registratie: April 2000
  • Laatst online: 22-08 20:24
Anders ik wel. :) Misschien als we samen even een gil geven. ;)

Ik ben vanmiddag even de deur uit, dus kijk ik vanavond weer even. Natuurlijk zal ik dan ook even verder Googlen.

Thanks voor het meedenken btw. B)

:Y)

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Je mag inderdaad geen instantie aanmaken van een parameter. Je kan als je richting de reflectie en type inspectie gaat maar heel weinig met Java Generics, wat precies ook het punt van kritiek is op deze voorstellen. Het is een (imho onjuist, in ieder geval vervelende) afweging die gemaakt is om de JVM en de Bytecode niet uit te breiden ten behoeve van Java Generics.

De oplossing is weer simpel: geef een Builder mee. Deze speelt in feite de rol van de constructor. Het is een generieke interface waarmee je concrete implementies kunt construeren.
code:
1
2
3
public interface Builder<O extends .. > {
    public O create( .... )
}

Via deze build kan je nu O's construeren, maar je zal dus wel voor elk type (in jouw geval voor elk attribuut) een concrete implementatie moeten maken. Ik gebruik deze techniek overal in mijn libraries en applicaties en het functioneert goed. Ik weet geen betere oplossing.

Dat je trouwens op die abstracte klasse uitkomt bij O.class klopt helemaal: generics worden gecompileerd door type-erasure: als er geen constraint is, betekent dit dat er gewoon gewerkt wordt met 'Object' en dat er gecast wordt waar nodig. Als er wel een constraint is, wordt er gewerkt met de constraint. In dit geval is dat dus Attribute.

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Je kan overigens wel een generieke, ranzige implementatie van die builder maken. Schetsje:

code:
1
2
3
4
5
6
7
8
9
10
11
class DirtyBuilder<O extends Attribute> implements Builder<O> {
  ...

  public Builder(Class class) {
     ...
  }

  public O create(int i) {
      Constructor constructor = ....
      return (O) constructor.newInstance( ...)
  }


Persoonlijk zou ik hier echter voor code generatie gaan ipv een ranzige generieke implementatie met nog een cast ook ;) .

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Leuk trouwens dat je ook echt Generics bent gaan gebruiken :) .

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • Tuinhark
  • Registratie: April 2000
  • Laatst online: 22-08 20:24
Ach ja.. je moet ook met je tijd mee gaan he? ;) Gekkigheid.

Ik werk nog steeds aan hetzelfde projectje en nu heb ik wel zo'n beetje overal die getypeerde (API) classes ingevoerd en moet zeggen dat ik het toch wel goed vind dat de compiler nu voor mij allerlei runtime checks voor mij kan doen. :) En zo heel lastig is het ook weer niet om het toe te passen (heel simpel gezegd, zo zie ik het vooralsnog). Er is volgens mij niet eens een reden om het niet te gebruiken.

Alleen die oplossing die je aandraagt voor mijn probleem... ik weet niet of ik die nu nog wel wil gebruiken. :/ Ik bedoel, ik heb nu een stuk of 30 subclasses (en het worden er mogelijk nog meer) en als ik daar nu die interface + alle impl classes bij moet maken.. Ik weet niet of dat de moeite waard is.

Of heb ik nu bepaalde zaken niet helemaal helder voor ogen? :?

:Y)

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Inderdaad is 30 'domme' implementaties maken niet bepaald een pretje... Daarom zou ik hier zelf code generatie gebruiken, maar in jouw situatie kan je misschien beter voorlopig even de 'ranzige' generieke Builder implementatie gebruiken (en dus wel werken via de Builder interface, die dus wel mooi is). Alleen de (enige) implementatie is dan een beetje vies...

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Met die factory methode zou je het probleem netjes kunnen oplossen en je kan toch gebruik maken van generics. Ik zou omwille van die constructor generics dus niet links laten liggen.

Maar vind het wel jammer dat die constructor eigelijk zo`n raar ding is en dat je daar dus geen voorschriften voor kan opstellen. Je loopt natuurlijk wel tegen allerlei beperkingen aan als je wel voorschriften op kan stellen maarja.. nu ook :)

En het zou misschien leuk zijn geweest als je statische net zo behandeld werden als niet statische methodes inclusief abstracte methodes, en overerven. Ik zie persoonlijk niet echt een logisch verschil tussen statische en niet statische methodes afgezien van het feit dat het bij de een gaat over een instantie van een class en bij de andere over de hele class. Het probleem zou dan ook opgelost zijn :)

  • Tuinhark
  • Registratie: April 2000
  • Laatst online: 22-08 20:24
Je hebt het door. :)

Anyway, die 'dirty builder' was voor mij een zet in de goede richting voor de huidige oplossing.

Like, behold! :P
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
public class AttributeCache<O extends Attribute>
{
    private final HashSet<O> _objects = new HashSet<O>();
    private final Class _type;

    public AttributeCache(Class type)
    {
        _type = type;
    }

    public synchronized boolean containsKey(int i)
    {
        try {
            get(i);
            return true;
        } catch (NoSuchElementException e) {
            return false;
        }
    }

    public synchronized O get(int id) throws NoSuchElementException
    {
        Iterator<O> iter = _objects.iterator();
        boolean found = false;
        O result = null;
        O step = null;

        while (!found && iter.hasNext())
        {
            step = iter.next();
            if (step.getSkill() == id)
            {
                result = step;
                found = true;
            }
        }

        if (!found)
            throw new NoSuchElementException("not found: " + id);

        return result;
    }

    public synchronized boolean put(O object)
    {
        if (object == null)
            throw new NullPointerException("null object");

        try {
            get(object.getSkill());
            return false;
        } catch (NoSuchElementException e) {
            _objects.add(object);
            return true;
        }
    }

    public synchronized int size() {
        return _objects.size();
    }

    public synchronized O newInstance(int i) throws InstantiationException
    {
        try
        {
            return get(i);
        }
        catch (NoSuchElementException e)
        {
            try
            {
                Constructor oConstr = _type.getConstructor(new Class[]{Integer.TYPE});
                O newInstance = (O)oConstr.newInstance(new Object[]{new Integer(i)});
                _objects.add(newInstance);
    
                return newInstance;
            }
            catch (InstantiationException e2)
            {
                throw e2;
            }
            catch (InvocationTargetException e2)
            {
                e2.getCause().printStackTrace();
                throw new InstantiationException();
            }
            catch (Exception e2)
            {
                InstantiationException eNew = new InstantiationException(e2.getMessage());
                eNew.setStackTrace(e2.getStackTrace());
                throw eNew;
            }
        }
    }
}


en

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public final class AttributeFactory
{
    private static AttributeCache<Winger> wingerHeap = new AttributeCache<Winger>(Winger.class);
    private static AttributeCache<Stamina> staminaHeap = new AttributeCache<Stamina>(Stamina.class);
    private static AttributeCache<Playmaking> playmakingHeap = new AttributeCache<Playmaking>(Playmaking.class);

...
...
...

    private AttributeFactory() {}

    public static Winger newWinger(int i) throws InstantiationException {
        return wingerHeap.newInstance(i);
    }

    public static Playmaking newPlaymaking(int i) throws InstantiationException {
        return playmakingHeap.newInstance(i);
    }

    public static Stamina newStamina(int i) throws InstantiationException {
        return staminaHeap.newInstance(i);
    }

...
...
...

}


Ik denk dat wel duidelijk is wat de bedoeling is, right? :) Zo hebben we het toch nog redelijk netjes opgelost vind ik.

And yet.. zit ik alweer verder te denken naar mogelijkheden om dit verder te optimaliseren. (Minder code om hetzelfde te bereiken == hogere mate van onderhoudbaarheid.) :P

:Y)

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Tuinhark: Anyway, die 'dirty builder' was voor mij een zet in de goede richting voor de huidige oplossing.
Inderdaad, dit is precies die oplossing alleen dan met een 'inline' builder ;) .

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment

Pagina: 1