Frage

import java.lang.reflect.Array;

public class PrimitiveArrayGeneric {
    static <T> T[] genericArrayNewInstance(Class<T> componentType) {
        return (T[]) Array.newInstance(componentType, 0);
    }

    public static void main(String args[]) {
        int[] intArray;
        Integer[] integerArray;

        intArray = (int[]) Array.newInstance(int.class, 0);
        // Okay!

        integerArray = genericArrayNewInstance(Integer.class);
        // Okay!

        intArray = genericArrayNewInstance(int.class);
        // Compile time error:
           // cannot convert from Integer[] to int[]

        integerArray = genericArrayNewInstance(int.class);
        // Run time error:
           // ClassCastException: [I cannot be cast to [Ljava.lang.Object;
    }    
}

Ich versuche zu verstehen, wie voll Generika in Java funktioniert. Die Dinge für mich ein bisschen komisch in der 3. Zuordnung in dem obigen Auszug: der Compiler beschwert sich, dass Integer[] nicht zu int[] umgewandelt werden. Die Aussage ist 100% wahr, natürlich, aber ich frage mich Warum die Compiler diese Beschwerde macht.

Wenn Sie diese Zeile kommentieren, und der "Vorschlag", wie er in der 4. Zuordnung des Compilers folgen, der Compiler tatsächlich erfüllt ist !!! NOW kompiliert den Code gerade fein ! Welches ist verrückt, natürlich, da wie das Laufzeitverhalten legt nahe, int[] nicht zu Object[] umgewandelt werden kann (was zur Laufzeit Typ löschte in dem, was T[] ist).

Also meine Frage ist: Warum ist der Compiler „darauf hindeutet,“ dass ich stattdessen für die 3. Zuordnung Integer[] zuweisen? Wie funktioniert der Compiler Grund, dass (irrtümlichen!) Schluss zu kommen?


Es gibt eine Menge Verwirrung in den beiden Antworten so weit, so dass ich eine weiteres verblüffendes Beispiel erstellt hier das zugrunde liegende Problem zu veranschaulichen:

public class PrimitiveClassGeneric {    
    static <T extends Number> T test(Class<T> c) {
        System.out.println(c.getName() + " extends " + c.getSuperclass());
        return (T) null;
    }
    public static void main(String args[]) {
        test(Integer.class);
        // "java.lang.Integer extends class java.lang.Number"

        test(int.class);
        // "int extends null"
    }
}

Bin ich der einzige, der es absolut verrückt denkt, dass der Compiler die oben genannten Code kompiliert können?

Es wäre nicht unvernünftig sein c.getSuperclass().getName() in dem obigen Code zu drucken, zum Beispiel, da ich die T extends Number angegeben. Natürlich jetzt getName() wird NullPointerException werfen, wenn c == int.class, da c.getSuperclass() == null.

Und mir, das ist ein sehr guter Grund, um den Code zu verwerfen von in erster Linie zu kompilieren.


Vielleicht ist der ultimative Wahnsinn:

    int.class.cast(null);

Dieser Code kompiliert und läuft gut.

War es hilfreich?

Lösung

Die Art der int.class ist Class<Integer>, so genericArrayNewInstance() gefolgert werden, würde eine Integer[] zurückzukehren. Aber die Funktion tatsächlich schafft eine int[], so dass es eine Klasse Guss Ausnahme haben würde, wenn es zurückgegeben. Grundsätzlich ist die Umwandlung in T[] innerhalb der Funktion nicht legitim in diesem Fall, da int[] ist kein T[] (Primitive nicht in Typ Variablen verwendet werden). Sie können nicht allgemein Typen primitive Array behandeln; so dass Sie entweder Ihre Methode haben müssen nur Typen Object zurückzukehren, oder müssen Sie verschiedene Methoden für Referenztypen und für primitive Typen machen.

Andere Tipps

Einige Punkte:

  1. Primitive sind autoboxed ihre Objekt Pendants (Wrapper) bei Bedarf
  2. primitive Arrays sind Objekte, so dass sie nicht autoboxed.
  3. Generika können nicht Primitive als Typparameter verwenden

Für Ihre Beispiele, hier sind meine Annahmen:

3 ist nun mal die Autoboxing mit dem Typparameter , aber nicht passiert zu dem zurückgegebenen Array
in 4 ist nun mal die Autoboxing mit dem Typparameter , aber nicht passiert zu der Methode Argument , so ist in der Tat ein int[] erzeugt, aber Integer[] wird erwartet,

Autoboxing im Fall von Typ-Parameter nicht genau sein könnte Autoboxing , ist aber etwas mit der gleichen Idee.

Update: Ihr zweites Beispiel hat nichts falsch. int.class ist ein Class, so dass der Compiler keinen Grund, sie abzulehnen hat.

Ich bin mit dem Original-Poster. Das ist verrückt. Warum kann ich primitive nicht mit Generika verwenden? Dies kann nicht Compiler Problem sein, aber es ist die Frage der Sprache. Einfach falsch von generischem Urtyp zu überspringen.

Für diese:

intArray = (int []) Array.newInstance (int.class, 0);

int.class ist nur ein Objekt der Klasse. So ist es in Ordnung übergehen. „Int“ ist eine Art, so dass es nicht in Ordnung, weil es klar primitiv ist. Um nicht zu sagen, das ist der „beste“ Weg, um die Sprache zu schaffen, nur um sie an die Sprache.

Das ist so verrückt, dass ich nicht einen Wrapper für Speicher (Array) Zuordnung von Primitiven mit Generika schaffen. Wenn Objekte verwenden, das ist so aufblasen für eine riesige Sammlung, die verschwenderisch ist. Menschen, die die Sprache Java / Maschine erstellt haben eindeutig ein wenig Grenze in ihrem Gehirn. Sie können es falsch machen das 1. Mal, aber Festsetzung dauert es zehn Jahre, und tun es nicht richtig.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top