2017-03-04 4 views
6

Ich habe diese generische Funktion:Rückgabetyp der generischen Methode (Java)

public static <T extends Number> T sum(List<T> list){ 
    Number tot = 0; 
    for(Number n: list){ 
     tot = tot.doubleValue() + n.doubleValue(); 
    } 
    return (T)tot; 
} 

Recall vom Haupt mit diesem Code:

public static void main(String[] args) { 
    ArrayList<Integer> listInt = new ArrayList<>(); 
    listInt.add(3); 
    listInt.add(5); 
    listInt.add(6); 
    listInt.add(8); 
    System.err.println("Sum: " + Calcolatrice.sum(listInt)) 
} 

ich daher erwarten (wobei listInt eine Arraylist von ganzen Zahlen) dass der von der Funktionssumme zurückgegebene Wert T = Integer ist und in diesem Fall ein Konvertierungsfehler von Double zu Integer gegeben ist. Der Typ des Ergebnisses ist stattdessen Double und kein Fehler wird ausgelöst. Die Besetzung (T) tot hat nicht das gewünschte Ergebnis.

Ich nehme an, es ist, weil Java Generics Standphase behandelt, aber jemand weiß besser erklären, warum es so funktioniert?

+4

[Typ Löschung] (https://docs.oracle.com/javase/tutorial/java/generics/erasure.html) ist der Begriff, der dieses Verhalten erklärt .... –

Antwort

1

Die Rückkehr Art von Calcolatrice.sum(listInt) ist eigentlich Integer dank der Besetzung am Ende sum in Ihrem Beispiel. Der tatsächliche Typ des Ergebnisses ist jedoch Double. Offensichtlich ist dies keine gute Situation, aber es ist passiert, weil Sie dem Compiler im Cast explizit gesagt haben, dass der Rückgabewert den gleichen Typ wie der Rückgabewert haben würde.

Diese Situation bedeutet, dass, wenn Sie stattdessen waren Calcolatrice.sum(listInt).toString() schreiben Sie würden eine ClassCastException: java.lang.Double cannot be cast to java.lang.Integer bekommen, weil Sie Integer.toString() auf einem Double aufrufen würde. Was Ihr Code tatsächlich macht, ist System.out.println("Sum: "+ String.valueOf(Calcolatrice.sum(listInt))), was funktioniert, weil es auf Object (so löst den Konflikt) vor dem Aufruf toString downcasts.

Wie @TmTron hervorhebt, können Sie nicht zwischen Double und Integer Box-Typen auf die gleiche Weise wie bei Primitiven umwandeln.

dh

int i = (int) 2.0; 

folgt anderen Regeln:

Integer i = (Integer) new Double(2.0) 
3

Die Generics sind nur bei der Kompilierung verwendet, um sicherzustellen, dass Sie keine Fehler im Code zu machen: Hier ist der Parameter List<T>, und der Empfang Variable muss von T Typ sein. Das ist alles.

Während der Laufzeit existiert T nicht, und tot ist keine Instanz von T; es ist ein Number.

Sie können innerhalb Ihrer Methode T verwenden, um die undefinierten Instanzen zu empfangen, aber Sie können beispielsweise keine new T() erstellen.

3

Wenn Sie an der Typenhierarchie betrachten, sehen Sie, dass sowohl Integer und Double Kinder Number sind: so sind sie Geschwister und Sie können nicht werfen direkt Double-Integer:

Double testDbl = 3.14; 
    Integer testInt = (Integer)testDbl; // this will NOT compile 

Der Compiler nicht sicher wissen kann, wenn die Besetzung in der return-Anweisung Ihrer sum Funktion funktioniert oder nicht: aber der Compiler eine Warnung:

Unchecked cast: 'java.lang.Number' to 'T' 

Weil von der Hard-Cast (T)tot, der Compiler wird es einfach als selbstverständlich betrachten, dass Ihre Funktion eine Integer zurückgibt (was es nicht tut).

Und schließlich, wegen type erasure, gibt es keine Laufzeitprüfung.

Verwandte Themen