2009-08-19 29 views
9

Jakie są korzyści wynikające z posiadania generycznego konstruktora dla klasy generycznej? Specyfikacja Java pozwala na:Korzyści z generycznych konstruktorów

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

Czy można wymyślić realistyczny przykład tego, kiedy zwiększa to bezpieczeństwo w klasie? Jak byłoby lepiej niż na ogół używać Generic?

Rozumiem, że projektanci Javy chcieli, aby konstruktorzy byli bardziej zgodni z metodami. Zważywszy, że konstruktorzy mogą mieć skutki uboczne, konstruktorzy generyczne mogą używać rodzajowych mutować pewne parametry, których referencje nie są zachowane, tak jak w

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

Odpowiedz

4

Jedynym obsłudze, że mogę myśleć byłoby, gdyby konstruktor potrzebny do używaj ogólnego obiektu podczas działania, ale nie zapisał tego obiektu, gdy był kompletny.

Na przykład:

<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()); 
    } 
} 

Jest to najprawdopodobniej po prostu coś, że projektanci język postanowił zrobić tylko w przypadku ktoś chciał go, ponieważ nie było żadnego powodu, aby uniemożliwić im to robić.

+0

Tak, pozwala na zastąpienie metod generycznych przez konstruktorów (ale dlaczego miałbyś chcieć?). Nigdy nie widziałem tego na wolności. Dla moich pieniędzy jest to komplikacja, której ten język by nie zrobił (tak jak C# zrobił później, gdy wprowadził swoją wersję generycznych Java). –

0

Tak, myślałem o tym samym kilka razy.

Hipotetycznie (jest 20 powodów, dla których tak nie jest) byłoby miło, gdyby generyczni konstruktorzy mogli zdefiniować formalny rodzajowy typ dla całej klasy (tak jak robi to deklaracja klasy ogólnej) ... To znaczy, jeśli definiuję Generic konstruktor pozwolił masz pola generycznych w tej klasie ...

na przykład, jeśli chcesz uniknąć uogólnienie:

EntityRequestCallback extends RequestCallback 

ale chciał RequestCallback być rodzajowy RequestCallback<E extends Entity>, nie można tego zrobić ponieważ tylko dwa typy żądania używają PUT/POST Entity. Tylko konstruktory żądań PUT/POST zawierają parametr Entity.

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; 
    } 
} 

Ale klasa nie może mieć charakter ogólny, ponieważ można byłoby stworzenie RequestCallback na żądanie, który nie ma podmiotu, co oznaczałoby byś instancję

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

więc, że jedynym możliwym sposobem tutaj jest generalizacji:

EntityRequestCallback<E extends Entry> extends RequestCallback 

Tak, że można mieć pola generic:

public E entity; 

W tym konkretnym przypadku, uogólnienie jest właściwym wyborem, ale są przypadki, w których uogólnienie nie byłoby.