2015-12-27 11 views
5

Ich spielte heute mit Java, und ich bemerkte etwas komisches. Betrachten Sie diesen Code:Java Casting-Methode, ohne zu wissen, was zu werfen

String foo = cast("hi"); 
int bar = cast("1"); 

Die cast() Methode ist hier:

public static <T> T cast(Object value) { 
    return (T) value; 
} 

Java "hi" in einen String zu werfen scheint, auch wenn ich keinen Hinweis bestanden hat, dass es ein String wäre, mit die Ausnahme des Typs. Es tut foo gut, aber schlägt auf bar fehl, weil Sie einen String nicht auf einen Integer anwenden können. Was passiert hier?

Ich habe zwei Annahmen:

  1. Das Gussverfahren ein Object zurückkehrt, und es wirft automatisch auf die bei der Initialisierung.

    Sinn Dies gilt nicht, wie es mir geben würde:

    Type mismatch: cannot convert from Object to int 
    
  2. Java scheint zu wissen, dass es zu String zu werfen braucht, oder was auch immer der Typ der Variablen ist. Aber wie funktioniert das?

+0

@KLibby Es ist in der Methode deklariert. Es heißt 'public static T cast (Objektwert) {'. Beachten Sie die ''. – TheCoffeeCup

+0

Die Klassendeklaration ist einfach 'public class Test {'. – TheCoffeeCup

+0

Die zweite gibt mir eine Laufzeitausnahme, kein Fehler bei der Kompilierung. Sprechen Sie darüber? – markspace

Antwort

6

Ihre Umwandlungsmethode erstellt eine unchecked conversion, die speziell in der JVM behandelt wird, um Abwärtskompatibilität mit nicht-generischem Code zu gewährleisten.

Solche Aufrufe können im Typsystem mit Generika nicht als statisch sicher angezeigt werden. Das Ablehnen solcher Aufrufe würde große Teile des vorhandenen Codes ungültig machen und sie daran hindern, neuere Versionen der Bibliotheken zu verwenden. JLS 5.1.9

die Methode ohne explizite Typparameter aufrufen wird der Compiler veranlassen, den Typ-Parameter der Anrufungen zu schließen, in diesem Fall auf der Grundlage ihrer erwarteten Rückgabetyp. Type Inference, JLS 15.12.2.7.. Dies bedeutet, dass Code wird diese equvivalent:

String foo = Caster.<String>cast("hi"); // no exception 
int bar = Caster.<Integer>cast("1"); // runtime ClassCastException 

Urtyp ihre Box-Version abgeleitet werden:

Wenn A eine primitive Art ist, dann ist A zu einem Referenz-Typ U über Boxen Umwandlung umgewandelt und dieser Algorithmus wird rekursiv auf die Einschränkung U angelegt < < F. JLS 15.12.2.7.

die JVM Sicherheit gewährleistet Typ von Laufzeittyp prüft dabei auf die Rückgabewerte von Funktionen co Wenn ich nicht markierte Abgüsse an dem ersten Punkt halte, wo die Typinformation nicht gelöscht wird (ich habe es nicht explizit in der Spezifikation gefunden, aber die Dinge scheinen so zu funktionieren, obwohl es in The Java Tutorials erwähnt wird). In diesem Fall, in dem Sie versuchen, den Wert einer typisierten lokalen Variablen zuzuweisen, wird der Typ des Rückgabewerts überprüft, was zu einer ClassCastException führt.

Um etwas mehr Idee zu geben, wenn die erzwungene Laufzeit Typprüfung Guss geschieht, sind hier ein paar Beispiele:

Object a3 = Caster.<String>cast(3); // no exception, a3 is now Integer 
Object a4 = (String)Caster.<String>cast(3); // an explicit cast causes runtime ClassCastException 

EDIT:

Hier ist eine Stackoverflow Frage, wann Laufzeittyp sind checks erzwungen: When is generic return value of function casted after type erasure?

7
public static <T> T cast(Object value) { 
    return (T) value; 
} 

Der wichtige Teil der <T> für das Verfahren ist, bedeutet dies, dass das Verfahren eine Art zurück auf das, was der Aufruf der Methode erwarten.

String foo = cast("hi"); // left side is a String, <T> will be typed as String 


Das zweite ist ein wenig komplizierter, da generische Typen nicht primitiven Typen sein kann. Ich denke, es gibt den häufigsten Typ Object zurück.

int bar = cast("1"); // left side is primitive 
        // <T> will be typed by with the corresponding non-primitive type. 
        // But it fails because "1" cannot be casted to java.lang.Integer 
+1

Ich denke für 'int', dass es tatsächlich in Integer umgewandelt wird. Das ist die Fehlermeldung, die ich bekomme: 'java.lang.ClassCastException: java.lang.String kann nicht in java.lang.Integer' umgewandelt werden. – markspace

+0

yeah, schöne Magie in der Luft :) ok, Primitive scheinen durch sie ersetzt zu werden primitive Klassen. @markspace thansk, ich habe meinen Fehler behoben. –

+0

@AnthonyRaymond Es heißt Auto-Unboxing –

0

Ich sehe kein seltsames Verhalten.

In:

String foo = cast("hi"); 

"hi" ist ein Object (wie alles in Java), so dass es durch den Compiler als Object Argument akzeptiert werden würde. Nach dem Aufruf gibt die Funktion cast() "hi" zurück, was eine Zeichenfolge ist, und sie wird String foo zugewiesen. Kein komisches Verhalten hier.

In:

int bar = cast("1"); 

"1" ist ein Objekt, und es wird vom Compiler akzeptiert. Die Funktion cast gibt "1" zurück, was eine Zeichenfolge ist. Im Gegensatz zu anderen Sprachen (z. B. Javascript) kann eine Zeichenkette nicht direkt als ganze Zahl angegeben werden. Kein komisches Verhalten hier.

Wenn Sie die cast() Funktion zu ändern:

public static <T> T cast(T value) { 
    return value; 
} 

Sie einen Fehler bei der Kompilierung erhalten, statt Ausführungszeit.

Verwandte Themen