Casts in Java (Casts in Java), Lektion, Seite 722343
https://www.purl.org/stefan_ram/pub/casts_java (Permalink) ist die kanonische URI dieser Seite.
Stefan Ram
Java-Kurs

Formungen in Java 

Eine Formung erlaubt es, den Typ eines Objektausdrucks unabhängig vom Typ seines Objektes einzustellen.

Dabei sind für den Typ eines Ausdrucks aber nur solche Typen erlaubt, die Obertypen des Typs des Objekts  sind.

Syntax

Der Formungsoperator ist ein unärer Präfix-Operator, der aus einem eingeklammerten Typnamen besteht.

Formungen elementarer Typen (wie »( int )«) wurden schon vor dem Aufbaukurs behandelt.

Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println( ( int )2.3 ); }}
Protokoll
2

Der Formungsoperator für Referenztypen

Im folgenden steht »T « für einen Referenztyp und »A« für einen Referenzausdruck.

Formungsregel Der Ausdruck »( T )A« hat den Typ »T «.

Main.java

public final class Main
{

public static void show( final java.lang.String s )
{ java.lang.System.out.println( "class java.lang.String" ); }

public static void show( final java.lang.CharSequence cs )
{ java.lang.System.out.println( "class java.lang.CharSequence" ); }

public static void show( final java.lang.Object o )
{ java.lang.System.out.println( "class java.lang.Object" ); }

public static void main( final java.lang.String[] args )
{

final java.lang.CharSequence cs = "abc";

show( ( java.lang.Object )cs );

show( ( java.lang.CharSequence )cs );

show( cs );

show( ( java.lang.String )cs ); }}

Protokoll
class java.lang.Object
class java.lang.CharSequence
class java.lang.CharSequence
class java.lang.String

Der Typ des referenzierten Objekts ändert sich durch die Formung nicht.

Main.java

public final class Main
{

public static void show( final java.lang.Object o )
{ java.lang.System.out.println( o.getClass() ); }

public static void main( final java.lang.String[] args )
{

final java.lang.CharSequence cs = "abc";

show( ( java.lang.Object )cs );

show( ( java.lang.CharSequence )cs );

show( cs );

show( ( java.lang.String )cs ); }}

Protokoll
class java.lang.String
class java.lang.String
class java.lang.String
class java.lang.String

Insofern „wandelt“ der Formungsoperator bei Referenztypen nichts, sondern legt nur den Typ des Ausdrucks fest.

Verallgemeinerungen (“upcasts ”)

Im folgenden steht »T « für einen Referenztyp und »A« für einen Referenzausdruck.

Formungsanforderung 0 Die Verwendung von »( T )A« ist erlaubt, wenn »T « ein Obertyp des Typs von »A « ist (“upcast ”).

Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ final java.lang.CharSequence cs = "abc";
java.lang.System.out.println( ( java.lang.Object )cs ); }}
Protokoll
abc

Der Begriff „Verallgemeinerung “ für einen upcast  ist nicht  allgemein üblich!

Spezialisierungen (“downcasts ”)

Im folgenden steht »T « für einen Referenztyp und »A« für einen Referenzausdruck.

Formungsanforderung 1 Die Verwendung von »( T )A« ist ebenfalls erlaubt, wenn »T « ein Untertyp des Typs von »A « ist und ein Obertyp des Typs des Objekts »A« ist (“downcast ”).

Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ final java.lang.CharSequence cs = "abc";
java.lang.System.out.println( ( java.lang.String )cs ); }}
Protokoll
abc

Der Begriff „Spezialisierung “ für einen downcast  ist nicht  allgemein üblich!

Verschiebungen (“sidecasts ”)

Im folgenden steht »T « für einen Referenztyp und »A« für einen Referenzausdruck.

Formungsanforderung 1 Die Verwendung von »( T )A« ist ebenfalls erlaubt, wenn »T « weder Untertyp noch Obertyp des Typs von »A « ist (“sidecast ”). Es muß aber weiterhin ein Obertyp des Typs des Objekts »A« sein.

Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ final java.io.Closeable c = java.lang.System.out;
java.lang.System.out.println( ( java.lang.Appendable )c ); }}
Protokoll
java.io.PrintStream@77468bd9

Der Begriff „Verschiebung “ für einen sidecast  ist nicht  allgemein üblich!

Prüfungen

Objektregel Der Typ eines Objektes muß ein Untertyp  des Typs eines Ausdrucks (also auch eines Namens) für das Objekt sein.

Bei einer Verallgemeinerung  ist die Objektregel automatisch erfüllt  (warum?). Wenn der Compiler erkennt, daß die Formungsanforderung 0 erfüllt wurde, legt er einfach den Typ des Ausdrucks neu fest. Beim Ablauf des Programms geschieht an dieser Stelle nichts (es geht keine Zeit verloren, während das Programm läuft).

Bei einer Spezialisierung  oder Verschiebung  ist es nicht  sicher, daß die Objektregel weiterhin erfüllt ist (warum?). Wenn der Compiler erkennt, daß die Formungsanforderung 0 nicht erfüllt ist, aber in einen Untertyp umgeformt wird, dann erzeugt er ein Programm, das beim Ablauf jedesmal prüft, ob die Objektregel erfüllt ist (kann Zeit kosten).

Verletzungen

Im folgenden Beispiel einer versuchten Spezialisierung ist die Objektregel verletzt, was erst zur Laufzeit erkannt wird.

Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ final java.lang.Object o = java.lang.System.out;
java.lang.System.out.println( ( java.lang.String )o ); }}
Protokoll
Exception in thread "main" java.lang.ClassCastException: java.base/java.io.PrintStream cannot be cast to java.base/java.lang.String
at Main.main(Main.java:4)

Eine Spezialisierung ist daher weniger eine Typwandlung  als eine Prüfung, bei der geprüft wird, ob das Objekt einen Untertyp des angegebenen Typs hat und das Programm andernfalls mit einer Fehlermeldung abgebrochen wird.

Im folgenden Beispiel einer versuchten Umformung ist der eingeklammerte Typ gar kein Ober- oder Untertyp seines Operanden. Eine solche „Verschiebung“ (bei welcher der Operandentyp weder Unter- noch Obertyp des Operatortyps ist) kann erlaubt sein, wenn das Objekt sowohl ein Untertyp von »java.lang.CharSequence« als auch von »java.lang.PrintStream« ist. Zur Laufzeit wird dann jedoch festgestellt, daß dies nicht der Fall ist.

Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ final java.lang.CharSequence cs = "abc";
java.lang.System.out.println( ( java.io.PrintStream )cs ); }}
Protokoll
Exception in thread "main" java.lang.ClassCastException: java.base/java.lang.String cannot be cast to java.base/java.io.PrintStream
at Main.main(Main.java:4)

Zuweisungen und Spezialisierungen

Java erlaubt keine Initialisierung oder Zuweisung mit einem Ausdruck eines Obertyps auf der rechten Seite. Wenn man sich jedoch sicher ist, daß das Objekt tatsächlich ein Untertyp des erwarteten Typs hat, dann kann man eine Spezialisierung verwenden.

Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ final java.lang.CharSequence cs = "abc";
final java.lang.String s = cs;
java.lang.System.out.println( s ); }}
Protokoll
Main.java:4: error: incompatible types: CharSequence cannot be converted to String
final java.lang.String s = cs; }}
^
1 error
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ final java.lang.CharSequence cs = "abc";
final java.lang.String s =( java.lang.String )cs;
java.lang.System.out.println( s ); }}
Protokoll
abc

Einsatzmöglichkeiten einer Verallgemeinerung

Der vorige Abschnitt zeigt eine Verwendung einer Spezialisierung.

Was aber könnte Anwendungen einer Verallgemeinerung sein?

Man kann damit beispielsweise steuern, welche Methode bei überladenen Methoden aufgerufen wird.

Main.java

public final class Main
{

public static void m( final java.lang.String s )
{ java.lang.System.out.println( "A: " + s ); }

public static void m( final java.lang.CharSequence cs )
{ java.lang.System.out.println( "B: " + cs ); }

public static void main( final java.lang.String[] args )
{

m( "abc" );

m( ( java.lang.CharSequence )"abc" ); }}

Protokoll
A: abc
B: abc

Jedoch könnte man dies auch – etwas umständlicher – durch Einführung eines Namens erreichen.

Main.java

public final class Main
{

public static void m( final java.lang.String s )
{ java.lang.System.out.println( "A: " + s ); }

public static void m( final java.lang.CharSequence cs )
{ java.lang.System.out.println( "B: " + cs ); }

public static void main( final java.lang.String[] args )
{

m( "abc" );

{ final java.lang.CharSequence cs = "abc"; m( cs ); }}}

Protokoll
A: abc
B: abc

 

Seiteninformationen und Impressum   |   Mitteilungsformular  |   "ram@zedat.fu-berlin.de" (ohne die Anführungszeichen) ist die Netzpostadresse von Stefan Ram.   |   Eine Verbindung zur Stefan-Ram-Startseite befindet sich oben auf dieser Seite hinter dem Text "Stefan Ram".)  |   Der Urheber dieses Textes ist Stefan Ram. Alle Rechte sind vorbehalten. Diese Seite ist eine Veröffentlichung von Stefan Ram. Schlüsselwörter zu dieser Seite/relevant keywords describing this page: Stefan Ram Berlin slrprd slrprd stefanramberlin spellched stefanram722343 stefan_ram:722343 Casts in Java Stefan Ram, Berlin, and, or, near, uni, online, slrprd, slrprdqxx, slrprddoc, slrprd722343, slrprddef722343, PbclevtugFgrsnaEnz Erklärung, Beschreibung, Info, Information, Hinweis,

Der Urheber dieses Textes ist Stefan Ram. Alle Rechte sind vorbehalten. Diese Seite ist eine Veröffentlichung von Stefan Ram.
https://www.purl.org/stefan_ram/pub/casts_java