Harten Cast vermeiden

marcolino

Mitglied
Hallo,

ich habe eine Frage zu einer von mir geschriebenen Klassenhierachie. Es geht um zwei Klassen, welche RGB-Farben kapseln.
Die Klassen habe ich mal unten eingefügt. Unelegant ist aus meiner Sicht die Methode setIntensity(Double). Diese wird in der Klasse RGBColor
definiert und hat den Rückgabetyp RGBColor. Innerhalb der Mathode wird eine Metode setColor aufgerufen, die den Wert zurückgibt.
Diese habe ich in der abgeleiteten Klasse GRBWColor überschrieben und der Rückgabetyp ist hier RGBWColor.
In der abgeleiteten Klasse RGBWColor#setIntensity muss ich aber jetzt einen Cast auf RGBWColor machen, damit es sauber kompiliert.

Frage : Wie kann ich das eleganter lösen ohne den Cast und ohne redundanten Code ?

Wäre über Hilfe sehr dankbar !

Gruss Marco

Java:
public class RGBColor
{
	
	private static final Integer MIN = Integer.valueOf(0);
	private static final Integer MAX = Integer.valueOf(255);
	protected static final MathContext MATH_CTX = new MathContext(3, RoundingMode.HALF_UP);
	
	public static final RGBColor GREEN = new RGBColor(0, 255, 0);
	
	
	private Integer red;
	private Integer green;
	private Integer blue;
	
	public RGBColor(Integer red, Integer green, Integer blue)
	{
		this();
		this.red = red;
		this.green = green;
		this.blue = blue;
	}
	
	public RGBColor()
	{
		super();
	}
	
	
	public Integer getRed()
	{
		return red;
	}
	public void setRed(Integer red)
	{
		this.red = red;
	}
	public Integer getGreen()
	{
		return green;
	}
	public void setGreen(Integer green)
	{
		this.green = green;
	}
	public Integer getBlue()
	{
		return blue;
	}
	public void setBlue(Integer blue)
	{
		this.blue = blue;
	}
	@Override
	public String toString()
	{
		return "red=" + red + ", green=" + green + ", blue=" + blue;
	}
	
	
	protected Integer limit(Integer value){
		if(value != null){
			value = value.compareTo(MIN) < 0 ? MIN : value;
			value = value.compareTo(MAX) > 0 ? MAX : value;
		}
		return value;
	}	
	
	public void limit(){
		setRed(limit(getRed()));
		setGreen(limit(getGreen()));
		setBlue(limit(getBlue()));	
	}
	
	public static RGBColor valueOf(String value)
	{
		RGBColor result = new RGBColor();
		String[] colors = value.split(",");
		result.setRed(Integer.valueOf(colors[0]));
		result.setGreen(Integer.valueOf(colors[1]));
		result.setBlue(Integer.valueOf(colors[2]));
		return result;
	}

	@Override
	public int hashCode()
	{
		return red.hashCode() + green.hashCode() + blue.hashCode();
	}

	@Override
	public boolean equals(Object obj)
	{
		if (obj instanceof RGBColor)
		{
			RGBColor other = (RGBColor) obj;
			return red.equals(other.red) && green.equals(other.green) && blue.equals(other.blue);
		} else
		{
			return false;
		}
	}	
	
	public RGBColor setIntensity(Double intensity)
	{
		Double maxIntensity = getMaxIntensity();
		if (maxIntensity.compareTo(Double.valueOf(0.0)) > 0)
		{
			return createColor(intensity, maxIntensity);
		} else {

			Integer newColor = Double.valueOf((255 * intensity) / 100).intValue();
		    return createColor(newColor);
		}
	}
	
	protected RGBColor createColor(Double intensity, Double maxIntensity)
	{
		return new RGBColor(
			getColorFromIntensity(intensity, red, maxIntensity),
			getColorFromIntensity(intensity, green, maxIntensity),
			getColorFromIntensity(intensity, blue, maxIntensity));
	}
	
	protected RGBColor createColor(Integer color)
	{
		return new RGBColor(color, color, color);
	}
	
	/**
	 * computes the intensity by the assigned color code.
	 * 
	 * @param colorValue the color value 0 <= x <= 255
	 * @return a percentage value 0 <= x <= 100.
	 */
	protected static Integer getColorFromIntensity(Double intensity, Integer colorValue, Double currentIntensity)
	{
		return  Double.valueOf(colorValue * intensity / currentIntensity).intValue();
	}

	public Double getMaxIntensity()
	{
		BigDecimal d = new BigDecimal(Math.max(Math.max(getIntensityFromColor(red), getIntensityFromColor(green)), getIntensityFromColor(blue)), MATH_CTX);
		return d.doubleValue();
	}
	
	/**
	 * computes the intensity by the assigned color code.
	 * 
	 * @param colorValue the color value 0 <= x <= 255
	 * @return a percentage value 0 <= x <= 100.
	 */
	public static Double getIntensityFromColor(Integer colorValue)
	{
		BigDecimal d = new BigDecimal(colorValue.doubleValue() * 100 / 255, MATH_CTX);
		return d.doubleValue();
	}
}



public class RGBWColor extends RGBColor
{
	private Integer white;

	public RGBWColor(Integer red, Integer green, Integer blue, Integer white)
	{
		super(red, green, blue);
		this.setWhite(white);
	}
	
	public RGBWColor()
	{
	}
	
	public RGBWColor(RGBColor rgbColor, Integer white)
	{
		this(rgbColor.getRed(), rgbColor.getGreen(), rgbColor.getBlue(), white);
	}
	

	public Integer getWhite()
	{
		return white;
	}

	public void setWhite(Integer white)
	{
		this.white = white;
	}

	@Override
	public String toString()
	{
		return super.toString() + ", white=" + white;
	}

	public static RGBWColor valueOf(String value)
	{
		RGBWColor result = new RGBWColor();
		String[] colors = value.split(",");
		result.setRed(Integer.valueOf(colors[0]));
		result.setGreen(Integer.valueOf(colors[1]));
		result.setBlue(Integer.valueOf(colors[2]));
		result.setWhite(Integer.valueOf(colors[3]));
		return result;
	}
	
	@Override
	public void limit(){
		super.limit();
		white = limit(getWhite());
	}

	@Override
	public int hashCode()
	{
		return super.hashCode() + white.hashCode();
	}

	@Override
	public boolean equals(Object obj)
	{
		if (obj instanceof RGBWColor)
		{
			RGBWColor other = (RGBWColor) obj;
			return super.equals(obj) && white.equals(other.white);
		} else
		{
			return false;
		}
	}

	@Override
	public Double getMaxIntensity()
	{
		BigDecimal d = new BigDecimal(Math.max(super.getMaxIntensity(), getIntensityFromColor(white)), MATH_CTX);
		return d.doubleValue();
	}

	@Override
	protected RGBWColor createColor(Double intensity, Double maxIntensity)
	{
		RGBColor rgbColor = super.createColor(intensity, maxIntensity);
		return new RGBWColor(rgbColor, getColorFromIntensity(intensity, white, maxIntensity));
	}

	@Override
	protected RGBWColor createColor(Integer color)
	{
		RGBColor rgbColor = super.createColor(color);
		return new RGBWColor(rgbColor, color);
	}

	@Override
	public RGBWColor setIntensity(Double intensity)
	{
		return (RGBWColor) super.setIntensity(intensity);
	}

	

}
 
Zuletzt bearbeitet von einem Moderator:
S

SlaterB

Gast
ich fürchte, eine gute Alternative wird es da nicht geben,
eine ziemlich aufwendige Variante mit Generics, für größere Geschütze vielleicht denkbar, hier eher noch schlimmer:
Java:
class RGBColor<T extends RGBColor>
{
....
    public T setIntensity(Double intensity)
    {
        Double maxIntensity = getMaxIntensity();
        if (maxIntensity.compareTo(Double.valueOf(0.0)) > 0)
        {
            return (T)createColor(intensity, maxIntensity);
        }
        else
        {

            Integer newColor = Double.valueOf((255 * intensity) / 100).intValue();
            return (T)createColor(newColor);
        }
        // evtl. lieber Rückgaben in einer Variablen speichern, nur am Ende einmal return (T)
    }
.....

class RGBWColor   extends RGBColor<RGBWColor>
{
...
// Methode nicht mehr zu überschreiben

------------

noch ein anderes Thema:
Java:
public class Test2
{
    public static void main(String[] args)
    {
        RGBColor a = new RGBColor(1, 2, 3);
        RGBWColor b = new RGBWColor(1, 2, 3, 4);

        System.out.println(a.equals(b));
        System.out.println(b.equals(a));
        System.out.println(a.hashCode() + " -- " + b.hashCode());
    }
}
ergibt als Ausgabe:
Code:
true
false
6 -- 10
zwei Objekte sind true/false je nachdem in welcher Richtung sie man vergleicht,
sie sind gar true trotz unterschiedlichen hashCode,
das widerspricht manchem Standard, allerdings ist dort auch nie so deutlich von unterschiedlichen Klassen die Rede,
meiner Erinnerung nach

solange du die Objekte schön nach Klassen getrennt hälst, ist wohl alles ok,
falls aber mal ein RGBColor- und ein RGBWColor-Objekt in derselben HashMap oder so landen...
 

Marco13

Top Contributor
Unelegant ist daram IMHO noch einiges mehr. Hat's einen besitmmten Grund, warum du überall die Wrapper-Typen (Integer, Double) statt der primitiven Typen (int, double) verwendest...?

Um nachzuvollziehen, was da gemacht wird habe ich (obwohl ich normalerweise relativ viel mit RGB-Farben rumhantiere) wohl noch zu wenig Koffein intus...
 

marcolino

Mitglied
Danke für Deine Antwort. Das Problem ist natürlich die equals Methode in RGBColor. Hier darf man nicht mit instanceof vergleichen, da sonst beim Aufruf mit RGBWColor Instanzen true zurückkommt. Ich habe es geändert, so dass jetzt auf die spezifischen Class Objekte geprüft wird. Dann funktioniert es wieder.

Gruss Marco
 

marcolino

Mitglied
Ich wüsste nicht warum ich nicht die Wrapper Objekte benutzen sollte. Ist ja nicht verboten ausser das die Performance evtl. etwas schlechter sein könnte, aber ich kann mir nicht vorstellen das dies ins Gewicht fällt.

Gruss Marco
 
S

SlaterB

Gast
spitzfindig:
wenn es keine Rolle spielt, dann schreibe dir doch noch noch weitere Wrapper IntegerInteger und verwende diese anstelle der normalen Integer,
warum? genau diese Frage ist eben gemeint, warum Integer statt int?

ein paar gewisse Nachteile sind ja schon jetzt vorhanden
Java:
return  Double.valueOf(colorValue * intensity / currentIntensity).intValue();
statt
return  (int) (colorValue * intensity / currentIntensity);
und anderes,

jemand könnte dir null reinmogeln, in limit() prüfst du gar auf != null, wieso?
wäre nicht eine Exception "GAU" im Falle des Erkennens eines null angebracht?
in equals usw. spätestens fliegen dir NullPointerExceptions um die Ohren, auch in der zuvor zitierten Rechnungszeile, quasi überall


wenn du aber auch gute Gründe hast, und sei es allein das Ablehnen primitiver Datentypen,
dann spricht natürlich nichts zwingend dagegen
 
Zuletzt bearbeitet von einem Moderator:

Marco13

Top Contributor
Ja, ich finde halt, dass es keinen Grund gibt, die Wrapper-Klassen zu verwenden, wenn man nicht explizit (wenige von ihnen!) in eine List<Integer> oder so packen will oder so. Abgesehen davon, dass ein [c]a>b[/c] sich eben leichter liest als ein [c]a.compareTo(b) > 0[/c]. Und ich finde, dass wenn bei der Repräsentation eines RGB-Wertes, bei dem unsere Vorfahren noch mit sich gehadert haben, ihn als int zu repräsentieren, weil da ja ein byte verschwendet wird, auf einmal BigDecimal auftaucht, etwas was falsch gelaufen ist. Aber vielleicht ist das eine ähnliche Form, sich auf die Vergangenheit zu beziehen, wie der Versuch, die Aussage aus den 1990ern, Java sei langsam, wieder auferstehen zu lassen :D

Die genaue (beabsichtigte) Funktion einiger Methoden ist mir (immernoch) unklar (setIntensity setzt nichts usw...), und ich glaube, dass bei der Vererbung in dieser Form auch Frau Liskov ( Liskov substitution principle - Wikipedia, the free encyclopedia ) anfangen würde, zu weinen, aber vielleicht täuscht das.

Aber um noch etwas semi-konstruktives zu sagen: Vielleicht ist der cast da gar nicht so schlimm...
 

marcolino

Mitglied
Ja, ich finde halt, dass es keinen Grund gibt, die Wrapper-Klassen zu verwenden, wenn man nicht explizit (wenige von ihnen!) in eine List<Integer> oder so packen will oder so. Abgesehen davon, dass ein [c]a>b[/c] sich eben leichter liest als ein [c]a.compareTo(b) > 0[/c]. Und ich finde, dass wenn bei der Repräsentation eines RGB-Wertes, bei dem unsere Vorfahren noch mit sich gehadert haben, ihn als int zu repräsentieren, weil da ja ein byte verschwendet wird, auf einmal BigDecimal auftaucht, etwas was falsch gelaufen ist. Aber vielleicht ist das eine ähnliche Form, sich auf die Vergangenheit zu beziehen, wie der Versuch, die Aussage aus den 1990ern, Java sei langsam, wieder auferstehen zu lassen :D

Die genaue (beabsichtigte) Funktion einiger Methoden ist mir (immernoch) unklar (setIntensity setzt nichts usw...), und ich glaube, dass bei der Vererbung in dieser Form auch Frau Liskov ( Liskov substitution principle - Wikipedia, the free encyclopedia ) anfangen würde, zu weinen, aber vielleicht täuscht das.

Aber um noch etwas semi-konstruktives zu sagen: Vielleicht ist der cast da gar nicht so schlimm...

setIntensity "dimmt" die aktuell eingestellte Fabe und ändert nicht den Zustand der vorleigenden Instanz, sondern gibt eine neue zurück mit den gedimmten Werten.
Wenn du z.B. einen Farbwert von Rot=255,Grün=0 und Blau = 0 hast, so wäre die Intensität dieser Farbe 100% (ausgehend von der hellsten Lampe => Rot). Setzt du diese jetzt auf 50%, so bleibenGrün und blau unverändert und Rot wird auf 127 gesetzt.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
H Object cast exception Allgemeine Java-Themen 5
Zeppi Cast Object in Generics Allgemeine Java-Themen 4
Tarrew RMI Java RMI - com.sun.proxy.$Proxy1 cannot be cast to Funktionen Allgemeine Java-Themen 0
G Klassen Cast auf Argumentenklasse via Reflection? Allgemeine Java-Themen 10
M Cast double[]-->Object[] oder Vector<double[]> Allgemeine Java-Themen 3
S Unchecked cast from Component to JComboBox<String> Allgemeine Java-Themen 3
P Reflection "Cast" Allgemeine Java-Themen 5
M cannot be cast to java.lang.Comparable Allgemeine Java-Themen 5
V Gibt es einen Variablen Cast? Allgemeine Java-Themen 8
Z Cast von Long zu Integer funktionert nicht Allgemeine Java-Themen 3
N cast über string Allgemeine Java-Themen 24
C int zu byte cast - verständnis Allgemeine Java-Themen 3
E Heap und Comparable (warning: [unchecked] unchecked cast) Allgemeine Java-Themen 2
MQue cast DefaultMutableTreeNode Allgemeine Java-Themen 2
M Type-Cast Allgemeine Java-Themen 3
G Cast Allgemeine Java-Themen 4
O unchecked cast? Allgemeine Java-Themen 4
S instanceof liefert true, aber cast funktioniert nicht! Allgemeine Java-Themen 6
reibi Unchecked cast Allgemeine Java-Themen 1
T cast Object to Double[] Allgemeine Java-Themen 2
G Trotz Generics Cast-Fehler! Allgemeine Java-Themen 5
G Object cast via Reflection Allgemeine Java-Themen 8
R cast Integer[] zu int[] Allgemeine Java-Themen 2
G Cast von String zu Enumeration Allgemeine Java-Themen 2
N Warning "The Cast from Object to" Allgemeine Java-Themen 9
D Cast schlägt fehl : Object[] zu Button[] Allgemeine Java-Themen 2
Y unnecessary cast & Performance Allgemeine Java-Themen 29
B unchecked cast Error Allgemeine Java-Themen 2
K Cast ohne neues Object zu erzeugen Allgemeine Java-Themen 12
D Cast Exeption Allgemeine Java-Themen 4
T JNI: jcharArray: warning: cast to pointer from integer of. Allgemeine Java-Themen 5
K Cast von Properties und Hashmap Allgemeine Java-Themen 9
E NumberFormatException bei cast auf double Allgemeine Java-Themen 5
H [unchecked] unchecked cast Problem Allgemeine Java-Themen 5
W Überflüssige Deklaration vermeiden...war da nicht mal was? Allgemeine Java-Themen 3
Zrebna Gibt es eine Möglichkeit eine NPE zu vermeiden, wenn null returned wird? Allgemeine Java-Themen 3
B einen color-chooser bauen, ähnliche Farben vermeiden Allgemeine Java-Themen 5
G Input/Output NIO.2: ShutdownChannelGroupException vermeiden Allgemeine Java-Themen 1
A Java - Beim Abspeichern Redundanzen vermeiden! Allgemeine Java-Themen 6
D java.util.ConcurrentModificationException - per Copy vermeiden Allgemeine Java-Themen 11
J Generics / vermeiden von downcasts Allgemeine Java-Themen 2
J instanceof vermeiden und stattdessen dynamisch binden Allgemeine Java-Themen 6
R java.util.ConcurrentModificationException vermeiden? Allgemeine Java-Themen 8
N Casten durch generic vermeiden ?? Allgemeine Java-Themen 10
M Vermeiden von instanceof Abfragen Allgemeine Java-Themen 3
B Pattern gesucht, Programm Optionen, Casten vermeiden Allgemeine Java-Themen 3
T Wie kann ich einen doppelstart vermeiden? Allgemeine Java-Themen 9
J instanceof vermeiden Allgemeine Java-Themen 10
T Concurrent Modification Exception vermeiden mit Prioritäten Allgemeine Java-Themen 4
B Vermeiden das JButton schneller hintereinander drücken Allgemeine Java-Themen 3

Ähnliche Java Themen

Neue Themen


Oben