Преимущество универсальных конструкторов - PullRequest
9 голосов
/ 19 августа 2009

В чем преимущество наличия универсального конструктора для неуниверсального класса? Спецификация Java допускает следующее:

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

Можно ли привести реальный пример того, когда это повышает безопасность типов класса? Как бы это было лучше, чем вообще использовать Generic.

Я понимаю, что разработчики Java хотели, чтобы конструкторы были более совместимы с методами. Учитывая, что конструкторы могут иметь побочные эффекты, универсальные конструкторы могут использовать универсальные шаблоны для изменения некоторых параметров, ссылки на которые не сохраняются, как в

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

Ответы [ 2 ]

5 голосов
/ 19 августа 2009

Единственное использование, которое я могу придумать, - это если конструктор должен использовать универсальный объект во время его работы, но не сохраняет этот объект после его завершения.

Например:

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

Скорее всего, это то, что разработчики языка решили сделать на тот случай, если кто-то этого хотел, так как не было никаких причин, чтобы люди не могли это сделать.

0 голосов
/ 12 октября 2011

Да, я думал об этом несколько раз.

Гипотетически (есть xx причины, по которым это не так) было бы неплохо, если бы конструкторы Generic могли определять формальный универсальный тип для всего класса (как это делает объявление универсального класса) ... То есть, если определить Generic конструктор позволит вам иметь общие поля в этом классе ...

Например, если вы хотите избежать обобщения:

EntityRequestCallback extends RequestCallback

но вы хотели, чтобы RequestCallback был универсальным RequestCallback<E extends Entity>, вы не могли этого сделать, потому что только два типа запроса PUT / POST используют Entity. Только конструкторы для запросов PUT / POST содержат параметр 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;
    }
}

Но класс не может быть универсальным, потому что вы создадите RequestCallback для запроса, который не имеет сущности, что означает, что вы создадите экземпляр

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

Так что единственный возможный путь здесь - обобщение:

EntityRequestCallback<E extends Entry> extends RequestCallback

Так что вы можете иметь общие поля:

public E entity;

В этом конкретном примере обобщение является правильным выбором в любом случае, но есть случаи, когда обобщение не будет.

...