[Generic] Problem bei Methodenüberladung.

Hallo liebe Community.

Zurzeit arbeite ich mit einem Freund an einem auf Java basierten Spiel. Da ich hauptsächlich in C# programmiere, will ich mir eine Eigenschaftenklasse machen, mit der ich ähnlich wie bei C# Eigenschaften nutzen kann.

Ich habe dafür 2 Klassen:
Java:
package SG;

/**
 * Eigenschaftsklasse zum vereinfachen von Eigenschaften einer Klasse.
 * @author Shinigami Games
 */
public class Property
{
    private boolean _readonly;
    private boolean _writeonly;
    protected Object _field;
    
    public Property()
    {
        this._readonly = false;
        this._writeonly = false;
        this._field = null;
    }
    
    public Property(Object DefaultValue)
    {
        this();
        this._field = DefaultValue;
    }
    
    public Property(Object DefaultValue, int AccessMode)
    {
        this(DefaultValue);
        switch (AccessMode)
        {
            case 1:
                this._readonly = true;
            case 2:
                this._writeonly = true;
        }
    }
    
    public static final int ReadOnly = 1;
    public static final int WriteOnly = 2;
    
    public Object Get()
    {
        if (this._readonly)
            return this._field;
        else return null;
    }
    
    public void Set(Object Value)
    {
        if (this._writeonly)
            this._field = Value;
    }
}

und
Java:
package SG.Generic;

/**
 * Eigenschaftsklasse zum vereinfachen von Eigenschaften einer Klasse.
 * @author Shinigami Games
 */
public class Property<PropertyType> extends SG.Property
{
    public Property()
    {
        super();
    }
    
    public Property(PropertyType DefaultValue)
    {
        super(DefaultValue);
    }
    
    public Property(PropertyType DefaultValue, int AccessMode)
    {
        super(DefaultValue, AccessMode);
    }
    
    @Override
    public PropertyType Get()
    {
        return (PropertyType)super.Get();
    }
    
    @Override
    public void Set(Object Value) throws ClassCastException
    {
        try
        {
            PropertyType TempValue = (PropertyType)Value;
            super.Set(Value);
        }
        catch (ClassCastException CastException)
        {
            throw new ClassCastException(CastException.getMessage());
        }
    }
    
    public void Set(PropertyType Value)
    {
        super.Set(Value);
    }
}

Jetzt sagt er mir die ganze Zeit:
Code:
error: name clash: Set(PropertyType) in SG.Generic.Property and Set(Object) in SG.Property have the same erasure, yet neither overrides the other
    public void Set(PropertyType Value)
  where PropertyType is a type-variable:
    PropertyType extends Object declared in class SG.Generic.Property

Ich bin nicht so erfahren in Java, allerdings sollte die Methode "Set(PropertyType)" doch eigentlich die Methode "Set(Object)" nur überladen, oder nicht?

Mfg
JustShinigami
 
Zuletzt bearbeitet:
Ich finde den Code schwierig bzw. schwer lesbar (aber nur meine Meinung). Deine Set Methode die du überschreibst, hat nicht die selbe Signatur -> Die eine wirft eine ClassCastException die andere nicht, vllt. liegt es daran. Einfach mal entfernen und testen. Achja das mit deinem AccessMode als int: Warum kein Enum?

Edit:

Der Code könnte dir vllt. helfen. Das sind die selben Klassen wie du hast nur typisiert. Dadurch sparst du dir casts und ähnliches. Außerdem hab ich ein Enum eingeführt. Mag das mit den ints nicht. Das mit dem extend kannst du dir nun auch sparen durch die typisierung

Code:
public class Property<PR> {
    private Set<AccessMode> accessModes = new HashSet<>();
    protected PR field;

    public Property() {
        this(null, AccessMode.NO_ACCESS);
    }

    public Property(PR defaultValue) {
        this(defaultValue, AccessMode.NO_ACCESS);
    }

    public Property(PR defaultValue, AccessMode... accessModes) {
        this.field = defaultValue;

        for (AccessMode accessMode : accessModes) {
            this.accessModes.add(accessMode);
        }
    }

    public Optional<PR> get() {
        return (accessModes.contains(AccessMode.READ_POSSIBLE) && !accessModes.contains(AccessMode.NO_ACCESS)) ? Optional.fromNullable(field) : Optional.<PR>absent();
    }

    public void set(PR value) {
        if (accessModes.contains(AccessMode.WRITE_POSSIBLE) && !accessModes.contains(AccessMode.NO_ACCESS)) {
            this.field = value;
        }
    }

    public static void main(String[] args) {
        Property<PropertyType> property = new Property<>(new PropertyType("Test"), AccessMode.READ_POSSIBLE, AccessMode.WRITE_POSSIBLE);
        property.set(new PropertyType("Test"));

        Optional<PropertyType> propertyTypeOptional = property.get();
        if (propertyTypeOptional.isPresent()) {
            System.out.println(propertyTypeOptional.get().getType());
        }

        property.set(new PropertyType("TEST2"));
        Optional<PropertyType> propertyTypeOptional2 = property.get();
        if (propertyTypeOptional2.isPresent()) {
            System.out.println(propertyTypeOptional2.get().getType());
        }
    }
}

Code:
public enum AccessMode {
    READ_POSSIBLE,WRITE_POSSIBLE,NO_ACCESS
}

Code:
public class PropertyType {
    private String type;
    
    public PropertyType(String type) {
        this.type = type;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }
}

Vllt. hilft dir das.
 
Zuletzt bearbeitet:
Was genau meinst du denn mit "schwer lesbar"? Also kommentartechnisch hab ich das noch nicht ganz auskommentiert, weil ich mehrere Projekte am laufen habe und die eine oder andere Klasse mal etwas ärmer kommentiert wird ^^"
Auch wenn ich es nicht überschreibe oder wenn ich nichts werfe, klappt es nicht.
Eigentlich brauche ich die Property-Basisklasse nicht, jedoch ist das kein 1-Mann-Projekt und die würden öfters auf das non-generische Property zugreifen. Blöd ist aber, dass Object viel zu allgemein für Typenbezogene Properties sind. Deshalb überschreibe ich die Basismethode und nutze die ClassCastException. Das Problem ist ya auch nicht die Methode, die ich überschreibe, sondern die, die ich überlade. Allerdings sehe ich gerade, dass ich die Überladungsmethode nicht mitkopiert habe -.-" :D
PS: Habe die generische Klasse im Startpost aktualisiert. *Zu blöd zum Copy&paste'n*

Mfg JustShinigami
 
Hallo,

naja, ist glaub ich ganz einfach, da alle Klassen von "Object" erben,

wird der Compiler immer mekkern, da "Object" genauso gut "PropertyType" sein kann und es daher nicht feststellen kann, was nun aufgerufen werden soll.

Nur weil die eine Methode Exceptions schmeisst, heisst es nicht, dass sich die Signatur der Methode verändert hat.

Bin ja auch kein Generics Freak, vielleicht solltest Du warten, bis die Java-Profis etwas dazu geäussert haben...

Grüße...
 
Hi,

das Problem liegt an den Methoden der Klasse Property in Zeile 31 und 44. Generics werden beim compilen entfernt, diese sind rein für den Programmierer da um ihn zu helfen.

Somit wird aus der Methode in Zeile 44 ein Set(Object), also die selbe Signatur die du in Zeile 31 verwendest, von daher die Fehlermeldung. Das ganze nennt sich "Type errasure".

Des weiteren fängst du in Zeile 38 eine ClassCastException und wirfst in Zeile 40 eine neue weiter. Hier geht dein Stacktrace verloren, was beim Debuggen anschließend sehr nervig sein kann. Nimm den Catch-Block komplett raus und lass die Exception einfach direkt raus fliegen.

Grüße,
BK
 
Hach, wie ich C# in diesem Fall vermisse ^^"
Java ist sowas von gar nicht mein Fall, muss ich ya sagen, also habe zwar ganz wenige Grundkenntnisse, aber werte Kollegen wollten ya Java. Mono war denen nicht global genug. Gut möglich, das PropertyType auch als Object erkannt wird und der Compiler meckert, allerdings ergibt das wenig sinn.. ^^"

EDIT: Oh, hab gerade deinen beitrag verpasst, Bratkartoffel ^^
Das ist ya mal richtig hart, was Java da anbietet. Das mit dem Catch block habe ich nun angepasst, allerdings löst es mein eigentliches Problem nicht, dass ich PropertyType als Parametertyp angeben kann. Ich könnt ya auch einfach die Standartmethode mit Object beibehalten, allerdings erscheint mir das eher "unsauberer" Code zu sein..

Gr.
JustShinigami
 
Zuletzt bearbeitet:
Ok, aber so könnte es gehen, hab grad ein bisschen rum geschraubt :)

Vielleicht ist ja das eine Anregung...


Java:
class MyProperty<T> extends Property
{
    public MyProperty()
    {
        super();
    }
    
    public MyProperty(T DefaultValue)
    {
        super(DefaultValue);
    }
    
    public MyProperty(T DefaultValue, int AccessMode)
    {
        super(DefaultValue, AccessMode);
    }
    
    @Override
    public T Get()
    {
        return (T) super.Get();
    }
    
    @Override
    public void Set(Object Value)
    {
        try
        {
            T TempValue = (T)Value;
            super.Set(Value);
        }
        catch (ClassCastException CastException)
        {
            throw new ClassCastException(CastException.getMessage());
        }
    }
    
    public void Set(PropertyType Value)
    {
        super.Set(Value);
    }
}

class Property<T>
{
    private boolean _readonly;
    private boolean _writeonly;
    protected T _field;
    
    public Property()
    {
        this._readonly = false;
        this._writeonly = false;
        this._field = null;
    }
    
    public Property(T DefaultValue)
    {
        this();
        this._field = DefaultValue;
    }
    
    public Property(T DefaultValue, int AccessMode)
    {
        this(DefaultValue);
        switch (AccessMode)
        {
            case 1:
                this._readonly = true;
            case 2:
                this._writeonly = true;
        }
    }
    
    public static final int ReadOnly = 1;
    public static final int WriteOnly = 2;
    
    public T Get()
    {
        if (this._readonly)
            return this._field;
        else return null;
    }
    
    public void Set(T Value)
    {
        if (this._writeonly)
            this._field = Value;
    }
}


class PropertyType
{
    ...
}
 
Ich frage mich gerade ganz ernsthaft, warum die Leute sich immer und immer wieder mehr Mühe machen etwas zu verpfuschen anstatt das Problem an der Quelle zu beseitigen ... In einem Betrieb, wo der suboptimale Code bereits durch die QS gegangen ist und abgenommen wurde, kann ich verstehen, dass es oft nicht so einfach ist einen bereits abgesegneten Code nochmal in eine andere Richtung zu verbiegen, aber das hier? Mach einfach Property generisch und dann hat sich das. Wenn keine explizite Typisierung vorgenommen wird, wird Java ohnehin mit Object arbeiten und damit bleibt das Verhalten erhalten, es wird lediglich zu einigen Warnungs kommen. Da, wo man den generischen Typ explizit angibt, da nutzt man eben Generics und alles ist gut. Mit diesem Rumgepfusche machst du dir im Endeffekt mehr Probleme, den Code komplizierter und haust zusätzlich unnütze Klassen ins System. Wenn es keinen sinnvollen Grund dafür gibt, dann änder einfach Property und damit hat sich das dann.
 
Die Property ist auch für meine Kollegen. Allerdings wollte ich mir mit dem Erben der Property klasse einfach das doppelt schreiben der Klasse vermeiden. Da ich ya ein C#-Programmierer bin, würde es hier natürlich auch klappen in c#, allerdings verhält sich Java leider ganz anders. Deshalb bin ich schon am rumspielen. Ich habe auch überlegt, einfach die generische Klasse "Property" unabhängig von der Klasse "Property" zu machen. Und frag mich nicht, warum die Object bevorzugen. Notfalls schreibe ich nur die generische Klasse und die hauen dann einfach nochmal "<Object>" dran, ist ya nicht zu viel verlangt.. :D
Danke auch dir, Akeshihiro.

Mfg
JustShinigami
 
Zurück