Für die Umwandlungen, die keinen Test zur Laufzeit benötigen, kann es möglich sein, dass der Compiler einige Optimierungen machen zur Laufzeit zu vermeiden Gießen.
Ich empfehle, die JLS Chapter 5. Conversions and Promotions zu lesen, um mehr über die Art der Konvertierungen zu erfahren, die einen Test zur Laufzeit benötigen.
Beispiel 5.0-1. Conversions zur Compile-Zeit und Laufzeit
A conversion from type Object to type Thread requires a run-time check to make sure that the run-time value is actually an instance of class Thread or one of its subclasses; if it is not, an exception is thrown.
A conversion from type Thread to type Object requires no run-time action; Thread is a subclass of Object, so any reference produced by an expression of type Thread is a valid reference value of type Object.
A conversion from type int to type long requires run-time sign-extension of a 32-bit integer value to the 64-bit long representation. No information is lost.
A conversion from type double to type long requires a nontrivial translation from a 64-bit floating-point value to the 64-bit integer representation. Depending on the actual run-time value, information may be lost.
5.1.6. Narrowing Reference Conversion:
Solche Umwandlungen erfordern einen Test zur Laufzeit, um herauszufinden, ob der Ist-Referenzwert ist ein legitimer Wert der neuen Art. Wenn nicht, wird eine ClassCastException ausgelöst.
5.1.8. Unboxing Conversion; Die Konvertierung wird zur Laufzeit fortgesetzt.
Siehe auch: 5.5.3. Checked Casts at Run-time
Es ist nicht so einfach zu bestimmen, wann die Umwandlung zum Beispiel geschehen:
public class Main {
private static class Child extends Parent{
public Child() {
}
}
private static class Parent {
public Parent() {
}
}
private static Child getChild() {
Parent o = new Child();
return (Child) o;
}
public static void main(final String[] args) {
Child c = getChild();
}
}
Das Ergebnis gegeben durch javap -c Main
ist:
public class Main extends java.lang.Object{
public Main();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: invokestatic #4; //Method getChild:()LMain$Child;
3: astore_1
4: return
}
Wenn Sie das ändern Methodendeklaration zu public static Child getChild()
das Ergebnis ist:
public class Main extends java.lang.Object{
public Main();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public static Main$Child getChild();
Code:
0: new #2; //class Main$Child
3: dup
4: invokespecial #3; //Method Main$Child."<init>":()V
7: astore_0
8: aload_0
9: checkcast #2; //class Main$Child
12: areturn
public static void main(java.lang.String[]);
Code:
0: invokestatic #4; //Method getChild:()LMain$Child;
3: astore_1
4: return
}
Sie sehen, dass nur die Änderung des Accessors, kann viel auf die möglichen Optimierungen auswirken.
Gute Frage ... aber ist es wichtig zu kodieren? Oder fragen Sie nur nach Ihrer eigenen Neugier? – Tenner
@Tenner spielt es eine Rolle? –
In diesem Beispiel erwarte ich, dass das Typcasting während der Kompilierungszeit ausgeführt wird und nicht während der Laufzeit. Sie sollten o jedoch nicht für die return-Anweisung in ein Child-Objekt umwandeln, da Java aufgrund des Objektdiagramms weiß, dass es vom Typ Kind ist. – Jay