2016-05-28 4 views
3

die folgenden Klassen gegeben ...Warum kann ich eine Liste eines Typs, der nicht in meiner Liste angegeben ist, zurückgeben? <T> Rückgabetyp?


package whoop.deduper; 

/** 
* @author deduper 
* 
*/ 
public class Foo { 

} 

package whoop.deduper; 


import java.math.BigDecimal; 
import java.util.Iterator; 
import java.util.List; 

/** 
* @author deduper 
* 
*/ 
public class FuBar { 

    public int fuBar(){ 

     Bar bar = new Bar(); 

     List<Foo> foos = bar.foos(); 

     int baz = 0; 

     for (Iterator iterator = foos.iterator(); iterator.hasNext();) { 

      BigDecimal foo = (BigDecimal) iterator.next(); 

      baz = foo.intValue(); 

      return baz; 

     } 

     return baz;  

    } 

} 

package whoop.deduper; 

import java.math.BigDecimal; 
import java.util.ArrayList; 
import java.util.Collections; 
import java.util.List; 

/** 
* @author deduper 
* 
*/ 
public class Bar { 

    public <T extends Foo> List<T> foos() { 

     List sketchy = new ArrayList(); 

     sketchy.add(BigDecimal.TEN); 

     return sketchy; 
    } 

} 

package whoop.deduper; 

import static java.lang.System.out; 

/** 
* @author deduper 
* 
*/ 
public class EffedUp { 

    /** 
    * @param args 
    */ 
    public static void main(String[ ] args) { 

     int effedUp = new FuBar().fuBar(); 

     out.println(effedUp + " — But it works!"); 

    } 

} 

... warum funktioniert das überhaupt? Ich meine, ich hätte irgendwo eine ClassCastException oder sowas erwartet! Warum ist nicht da?

Kann mir bitte jemand eine klar geschriebene Erklärung geben, die dokumentiert, was hier vor sich geht?

Vielen Dank im Voraus.

+3

Sie können wegen dieses Rohtyps 'List sketchy = new ArrayList();'. Auch Ihre IDE sollte Sie über diese Rückkehr in 'Bar # foos' warnen. – Tom

Antwort

1

Eine Variable vom Typ List<Foo> garantiert nicht, dass Sie tatsächlich eine Liste von Foos haben. Sie werden nur sicherstellen, wenn Sie versuchen, Foos herauszuziehen, was Sie nicht sind, Ihr Iterator ist kein Iterator<Foo> und Sie werfen nicht auf Foo überall. Wenn Sie den Compiler das Casting für Sie ausführen lassen, wird es wie erwartet unterbrochen.

List<Foo> foos = bar.foos(); 

    int baz = 0; 

    for (Foo foo : foos) { 
    System.out.println(foo); // ClassCastException 
    } 

Wenn Sie mit dem „normalen“ Weg zu gehen, wie oben gezeigt, wird der Compiler selbst einen Iterator bekommen und warf jedes Element zu Foo und damit der obigen Code würde scheitern, wenn die Liste nicht leer ist.

Ihr Code zeigt, wie schlecht raw-types sind und warum man sie immer vermeiden sollte.

-1
List l = new ArrayList(); 
    List<Integer> ints = l; 

Wenn Sie die Zuordnung machen, werden Sie Java sagen die Adresse l in ints und nichts mehr zu setzen. Dies geschieht zur Laufzeit, wenn Generika aus dem Code gelöscht werden.

Generics werden vom Compiler zur Kompilierzeit verwendet, wenn der Compiler versucht, mögliche typbezogene Fehler zu identifizieren. Es stürzt beim Kompilieren nicht ab, weil er nicht weiß, welche Werte in der Liste gespeichert sind, weil keine angegeben wurden. Es stürzt zur Laufzeit mit ClassCastException ab, wenn die Liste unerwartete Elemente enthält (denn nur zur Laufzeit haben Sie die Objekte).

Ich kann nicht den Grund herausfinden, warum sie dies zur Kompilierzeit zugelassen haben. Ich hätte einen Kompilierfehler erwartet, wenn der Compiler so etwas gefunden hätte. Anstelle eines Fehlers erhalten Sie Warnungen.

Wenn Sie die Zuordnung machen, werden Sie einfach I give you a list, doesn't matter what it has inside, you just store it sagen.

Als Hinweis geben Sie immer den Typ einer Liste an. In Ihrem Fall List<T>. Denken Sie daran, solange Sie keine Liste mit vielen Objekttypen haben müssen, die meiner Erfahrung nach selten sind.

Verwandte Themen