# unnecessary cast & Performance



## youssef (25. Okt 2006)

Hallo Zusammen,
ich habe in einer Applikation, die ich verwende viele Unnecessary cast Warnungen . ich arbeite mit eclipse 3.2.
ein Beispiel:



```
public class A
{
}

public class B
{
.....
private static  A a

public static A f(double d)
{
.....
return(A)a;//unnecessary cast
}

}

public class C
{
......
int i=5;
A a = B.f((double)i);//unnecessary cast
}
```
ich habe gelesesen dass diese unnecessary cast at run time zeit kosten.
machen diese unnecessary cast wirklich die Performance schlechter ? habt ihr quellen dazu ?

danke im voraus
Youssef


----------



## SnooP (25. Okt 2006)

ich dachte eigentlich, dass die der Compiler rausfischen kann, denn immerhin erkennt sie ja auch eclipse durch eine entsprechende Analyse... - von daher glaub ich fast gar nicht, dass das Performance schlechter macht... - abgesehen davon wäre das sicherlich minimal und kaum messbar...

aaaber... warum hast du die überhaupt drin? Imho machen diese Casts das ganze nicht lesbarer...


----------



## AlArenal (25. Okt 2006)

Nein, das kann der Compiler nicht immer rausfischen. Du kannst doch zur Laufzeit beliebige Object Instanzen in eine Collection schieben, auslesen und casten. Wäre das allein durch den Compiler immer eindeutig, gäbe es keine ClassCastException zur Laufzeit. Erst mit Generics (Java 5) hat man eien Möglichkeit zur Compile-Time Typsicherheit für typisierten Kram zu prüfen und zu gewährleisten.


----------



## byte (25. Okt 2006)

Naja, aber Unnecessary Casts sind halt nur diejenigen, die wirklich unnötig sind. Und ich denke auch, dass der Compiler die eh wegoptimiert.


----------



## SnooP (25. Okt 2006)

Eben... die von dir beschriebenen Casts sind ja nicht unnecessary?


----------



## AlArenal (25. Okt 2006)

Einigen wir uns darauf, dass es keinen Sinn macht eine Referenz in ihren eigenen Typ zu casten und sich daraus ergibt, dass man sich auch keine Gedanken machen muss, obs Performance kostet oder nicht 

Das ist wie: 
Frage: In Brasilien ist dem Benzin Ethanol beigemischt. Wirkt sich das auf die Leistung meines Wagens aus?
Antwort: Nein, denn du tankst in Deutschland.

Also Youssef, tanke in Deutschland, dann brauchste dir auch keinen Kopf um Motorleistung in Brasilien machen


----------



## youssef (25. Okt 2006)

danke an alle für eure antworten

@AlArenal
diese cast Operationen kommen nicht von mir (ich habe sie nicht eingebaut), sondern waren schon drin in der Applikation, die ich weiterpflegen muss.
Eclipse zeigt wegen der Compiler Setting Warnungen in diesen Stellen.
ich habe mir nur gefragt ob es Sin macht (den Aufwand wert ) diese Casting raus zunehmen oder nicht:
Performance, Lesbarkeit und ...


Youssef


----------



## AlArenal (25. Okt 2006)

Ich kann mir ehrlich gesagt nicht vorstellen, dass diese Casts Performance kosten. Allerdings habe ich auch keine Lust mir nun schwre Kost anzutun und mich in die Umsetzung der VM einzulesen. Wenn einer Bock hat, kann er ja mal Beispielcode mit und ohne überflüssigen Cast machen, kompilieren und den Bytecode vergleichen.

Das würde aber auch nru klären, obs Platz kostet. Da die aktuellen VMs alle on-the-fly das Programm untersuchen und auf die jeweilige Plattform hin optimieren, sagt das allein noch nichts über Performance Penaltys aus.


----------



## SnooP (25. Okt 2006)

Gibt es da kein fertiges Refactoring für? Weil wenn Eclipse schon Warnings dafür ausspucken kann, dann könnte man die ja gleich entfernen lassen... in dem Fall ist das ja wirklich nur nen einfaches replace.

zur performance... - muss nicht die Methode selbst intern sowas wie nen cast machen? Also quasi implizit, während dieser cast bei einem explizitem Cast beim Aufrufen der Methode ja entfällt... ergo sollte ziemlich genau die gleiche Sache rauskommen...


----------



## byte (25. Okt 2006)

Seit Eclipse 3.2 _Project -> Source -> Clean Up -> Unnecessary Code -> Remove unnecessary casts_


----------



## Leroy42 (2. Nov 2006)

AlArenal hat gesagt.:
			
		

> Allerdings habe ich auch keine Lust mir nun schwre Kost anzutun und mich in die Umsetzung der VM einzulesen. Wenn einer Bock hat, kann er ja mal Beispielcode mit und ohne überflüssigen Cast machen, kompilieren und den Bytecode vergleichen.



Zu beidem habe ich auch keine Lust, aber ich denke -- ungeprüft -- das man
hierbei mit _gesundem Vorstellungsvermögen_ zu einer Lösung kommt.



			
				AlArenal hat gesagt.:
			
		

> Du kannst doch zur Laufzeit beliebige Object Instanzen in eine Collection schieben, auslesen *und casten*.



Genau das bezweifle ich stark. Soweit ich mich in die JVM hineinversetzen kann,
gibt es überhaupt keinen _Code zum casten_. Der Cast dürfte _ausschließlich_
eine Angelegenheit zur Compile-Zeit für den Compiler sein, dem damit _versprochen_ wird
auf Methoden/Instanzvariablen der entsprechenden Klassendefinition zur Laufzeit _zugreifen zu dürfen_.
Nach dem Kompilieren dürfte keine Spur mehr von diesem Cast zu finden sein.




			
				AlArenal hat gesagt.:
			
		

> Wäre das allein durch den Compiler immer eindeutig, gäbe es keine ClassCastException zur Laufzeit.


Auch hier ist meine Meinung, daß die ClassCastExceptions nicht beim casten selbst,
der ja nach meinen obigen Ausführungen zur Laufzeit gar nicht existiert, geworfen wird,
sondern direkt durch die Zugriffe auf nicht-vorhandene Methoden/Instanzvariablen.


----------



## Wildcard (2. Nov 2006)

Wie du an Methodenüberladung erkennen kannst spielen casts zur Laufzeit eine Rolle.


----------



## Wildcard (2. Nov 2006)

Beispiel:

```
public class Casts
{
    public static void main(String[] args)
    {
        Object o = "";
        print(o);
        print((String)o);
    }
    
    public static void print(Object o)
    {
        System.out.println("Objekt");
    }
    
    public static void print(String s)
    {
        System.out.println("String");
    }
}
```


----------



## SlaterB (2. Nov 2006)

ist das nicht eher eine Unterscheidung nach Typ des Objektes?
dabei müssen ja nicht unbedingt Casts zum Einsatz kommen

(unwissend in den Wind gesprochen)

edit: na dieses Beispiel ist ja extrem unpassend,
da wird doch evtl. nur zur Kompilierzeit die eine oder andere Operation ausgewählt?

mag sein dass es am cast liegt, 
aber das beweist das Programm nicht,
das könnte auch der Kompiler gewesen sein


----------



## Wildcard (2. Nov 2006)

Wie du siehst hat der Cast hier einen Einfluss, was bedeutet das er auch zur Laufzeit ausgeführt wird, da das Objekt ja immer noch das selbe ist.


----------



## Leroy42 (2. Nov 2006)

Wildcard hat gesagt.:
			
		

> Wie du an Methodenüberladung erkennen kannst spielen casts zur Laufzeit eine Rolle.



Auch das wird zur Laufzeit erkannt


```
void x(int i);
void x(long l);
```
unterscheidet sich ja alleine schon durch die Methodenadressen
_innerhalb_ einer Klasse.

Wenn du auf Vererbung anspielst, dann wird dies durch die
virtuelle Tabelle der Methodenzeiger erledigt.

*((A) myBInstance).doSomething();
myBInstance.doSomething();*
rufen *dieselbe* Methode auf (nämlich die von B) falls
B von A erbt und _doSomething()_ überschreibt.
Der Cast hierbei ist für die Katz'.


----------



## SlaterB (2. Nov 2006)

@Wildcard

na dieses Beispiel ist ja extrem unpassend,
da wird doch evtl. nur zur Kompilierzeit die eine oder andere Operation ausgewählt?

mag sein dass es am cast liegt,
aber das beweist das Programm nicht,
das könnte auch der Kompiler gewesen sein


----------



## Wildcard (2. Nov 2006)

Und wie erklärst du das bei Reflection-Casts?

@Leroy42
siehe mein Beispiel.


----------



## SlaterB (2. Nov 2006)

what the hell ist a Reflection-Cast, falls an mich gerichtet


----------



## Leroy42 (2. Nov 2006)

Wildcard hat gesagt.:
			
		

> was bedeutet das er auch zur Laufzeit ausgeführt wird, da das Objekt ja immer noch das selbe ist.


Das Objekt ist dasselbe aber der Compiler konnte schon zur Laufzeit die Methode
festlegen die aufgerufen wird.



			
				Wildcard hat gesagt.:
			
		

> Und wie erklärst du das bei Reflection-Casts?



Das gibt es auch nur zur Compile-Zeit, da es zur Laufzeit sowieso nur
Objekte vom Typ Object gibt.


----------



## Roar (2. Nov 2006)

leroy hat teilweise recht, die methoden die aufgerufen werden, werden zur compile zeit festgelegt, aber darin, dass der "cast" auch im bytecode vermerkt wird, sind wir uns ja einig, sonst würde keine classcast exception fleigen.


----------



## Wildcard (2. Nov 2006)

```
public class Casts
{
    public static void main(String[] args)
    {
        
        Object o = "";
        print(o);
        print(String.class.cast(o));
    }
    
    public static void print(Object o)
    {
        System.out.println("Objekt");
    }
    
    public static void print(String s)
    {
        System.out.println("String");
    }
}
```
Ich glaube nicht das ein solches Konstrukt Compilermagic ist.


----------



## Roar (2. Nov 2006)

Wildcard: schau dir mal die methode cast() an, die arbeitet mit generics, die zur compilezeit aufgelöst werden. der resultierende bytecode ist also im prinzip identisch mit dem von print((String) o) (abgesehen von Class objekt laden unc cast() aurufen):


```
Object o = "";
        print(o);
		print((String) o); 
		print(String.class.cast(o));
```


```
0:   ldc     #2; //String
   2:   astore_1
   3:   aload_1
   4:   invokestatic    #3; //Method print:(Ljava/lang/Object;)V
   7:   aload_1
   8:   checkcast       #4; //class java/lang/String
   11:  invokestatic    #5; //Method print:(Ljava/lang/String;)V
   14:  ldc_w   #4; //class java/lang/String
   17:  aload_1
   18:  invokevirtual   #6; //Method java/lang/Class.cast:(Ljava/lang/Object;)Lj
ava/lang/Object;
   21:  checkcast       #4; //class java/lang/String
   24:  invokestatic    #5; //Method print:(Ljava/lang/String;)V
```


----------



## Leroy42 (2. Nov 2006)

Roar hat gesagt.:
			
		

> leroy hat teilweise recht, die methoden die aufgerufen werden, werden zur compile zeit festgelegt, aber darin, dass der "cast" auch im bytecode vermerkt wird, sind wir uns ja einig, sonst würde keine classcast exception fleigen.



Hab's mal getestet und bin jetzt überzeugt.

```
public class Test extends Frame {
	public static void main(String args[]) {
		Object o =  new Integer(42);
		String s = (String) o;
		System.out.println("Hallo");
		s.indexOf('Z');
	 }
 }
```

liefert zur Laufzeit eine ClassCastException in *Zeile 4*; nicht erst
in Zeile 6 wie ich erwartet hätte.

Trotzdem ist mir jetzt nicht klar, wie die JVM überhaupt die
ClassCastException erkennt. Meines bisherigen Wissens nach,
kennt Java den Typ zur Laufzeit doch nicht.

Bin im Moment total durcheinander!  :autsch:  ???:L


----------



## Wildcard (2. Nov 2006)

Jau, ich seh's gerade. Dachte eigentlich die Methode gab's schon vor Java5...  
Klärt trotzdem nicht die Frage ob der Compiler casts durch geschicktes linken auflöst oder 'cast' zur Laufzeit exisitieren. 
Bleiben wohl nur die specs.


----------



## Roar (2. Nov 2006)

Leroy: jedes Object in der VM kennt doch sein Class Objekt, also auch seinen Typ, damit sollte das dann ja kein Problem mehr sein den cast zu überprüfen 

ahja: "
liefert zur Laufzeit eine ClassCastException in Zeile 4; nicht erst
in Zeile 6 wie ich erwartet hätte. " also da der cast in zeile 4 durchgeführt wird - jedenfalls in meinem code - erwarte ich auch dass die vm dort mir meine excfeption wirft, ansonstern viel spaß beim fehler suchen :bae:

Wildcard: Generics werden eigentlich alle zur compile zeit geprüft und aufgelöst, wie man am bytecode auch erkennen kann


----------



## SlaterB (2. Nov 2006)

auch Eclipse kann das,
wenn man da jeweils 'Open Declaration' aufruft kommt man zur einen oder anderen Operation


----------



## Wildcard (2. Nov 2006)

Bei generics ist das auch ne klare Sache  :wink:


----------



## byte (2. Nov 2006)

Leroy42 hat gesagt.:
			
		

> Trotzdem ist mir jetzt nicht klar, wie die JVM überhaupt die
> ClassCastException erkennt. *Meines bisherigen Wissens nach,
> kennt Java den Typ zur Laufzeit doch nicht.*



Heureka, wie kommst Du denn auf sowas? Ausschließlich _generische_ Typinformationen sind zur Laufzeit nicht mehr verfügbar.


----------



## Leroy42 (3. Nov 2006)

byto hat gesagt.:
			
		

> Ausschließlich _generische_ Typinformationen sind zur Laufzeit nicht mehr verfügbar.



Das werde ich wohl verwechselt haben.


----------

