2009-08-19 12 views
9

Welchen Vorteil hat ein generischer Konstruktor für eine nicht generische Klasse? Java-Spezifikation ermöglicht die folgende:Vorteil von generischen Konstruktoren

class NonGeneric { 
    <T> NonGeneric() { } 
    ... 
    NonGeneric ref = new <String> NonGeneric(); 
} 

Kann man mit einem realistischen Beispiel kommen, wenn es die Typsicherheit der Klasse verbessert? Wie wäre es besser als die Verwendung von Generic in erster Linie.

Ich verstehe, dass Java-Designer die Konstruktoren mehr mit Methoden konsistent sein wollten. Da Konstrukteure können Nebenwirkungen haben, generische Konstrukteure Generika verwenden können einige Parameter, deren Referenzen werden nicht beibehalten mutieren, wie in

<T> NonGeneric(T obj, List<T> list) { 
    list.add(obj); 
    // Don't hold a reference to list 
} 

Antwort

4

Die einzige Anwendung, die ich würde denken kann, wenn der Konstruktor benötigt Verwenden Sie ein generisches Objekt, während es ausgeführt wurde, aber speicherte das Objekt nicht, sobald es abgeschlossen war.

Zum Beispiel:

<T> NonGeneric(T[] blank, List<T> list) { 
    // Sort that list 
    T[] array = list.toArray(blank); 
    Arrays.sort(array); 

    // Pull out the values as strings 
    this.list = new ArrayList<String>(array.length); 
    for (T value : array) { 
     this.list.add(value.toString()); 
    } 
} 

Es ist sehr wahrscheinlich nur etwas, das die Sprachdesigner tun beschlossen, nur falls jemand es wollte, da es keinen Grund gab, Menschen daran zu hindern, es zu tun.

+0

Ja, es erlaubt generische Methoden, durch Konstruktoren ersetzt zu werden (aber warum möchten Sie?). Ich habe noch nie einen in freier Wildbahn gesehen. Für mein Geld ist es eine Komplikation, auf die die Sprache hätte verzichten können (wie C# später, als es seine Version von Java-Generika einführte). –

0

Ja, ich dachte ein paar Mal über dasselbe nach.

Hypothetisch (es gibt xx Gründe, warum es nicht so ist) wäre es nett, wenn Generische Konstruktoren formalen generischen Typ für die ganze Klasse definieren könnten (wie generische Klassendeklaration tut) ... Das heißt, wenn definierend Generisches Konstruktor würde Sie in dieser Klasse generische Felder haben ...

zum Beispiel, wenn Sie Generalisierung vermeiden wollte:

EntityRequestCallback extends RequestCallback 

aber wollte man die RequestCallback generic RequestCallback<E extends Entity> sein, könnten Sie das nicht tun, weil nur zwei Arten von Anfragen PUT/POST Entity verwenden. Nur Konstruktoren für PUT/POST-Anforderungen enthalten Entity-Parameter.

public class RequestCallback { 

     /** GET/DELETE requests */ 
    public RequestCallback(String gttUrl, HttpMethod method,) { 
     this.gttUrl = gttUrl; 
       this.method = method; 
    } 

     /** PUT/POST requests */ 
    public RequestCallback(String gttUrl, HttpMethod method, Entity entity) { 
     this.gttUrl = gttUrl; 
       this.method = method; 
     this.entity = entity; 
    } 
} 

Aber die Klasse kann nicht generisch sein, weil Sie RequestCallback für eine Anforderung zu schaffen wäre, dass keine Einheit hat, die Sie

new RequestCallback(); //without specifying generic parameter - worse than nothing 

So würde instanziiert bedeuten würde, dass die einzige Möglichkeit, hier ist Verallgemeinerung:

EntityRequestCallback<E extends Entry> extends RequestCallback 

Damit Sie generische Felder haben:

public E entity; 

In diesem speziellen Beispiel ist die Verallgemeinerung die richtige Wahl, aber es gibt Fälle, in denen Generalisierung nicht wäre.