Подтвердить что ты не робот

Какую цель выполняют общие конструкторы в Java?

Как известно, у вас может быть общий класс в Java с помощью аргументов типа:

class Foo<T> {
    T tee;
    Foo(T tee) {
        this.tee = tee;
    }
}

Но вы также можете иметь общие конструкторы, означающие конструкторы, которые явно получают свои собственные аргументы общего типа, например:

class Bar {
    <U> Bar(U you) {
        // Why!?
    }
}

Я изо всех сил пытаюсь понять прецедент. Что эта функция позволяет мне делать?

4b9b3361

Ответ 1

Что эта функция позволяет мне делать?

Есть, по крайней мере, three две вещи, которые он позволяет вам делать, иначе вы не могли:

  • выражают отношения между типами аргументов, например:

    class Bar {
        <T> Bar(T object, Class<T> type) {
            // 'type' must represent a class to which 'object' is assignable,
            // albeit not necessarily 'object' exact class.
            // ...
        }
    }
    
  • < отозванa >

  • Как заметил @Lino, он позволяет вам выразить, что аргументы должны быть совместимы с комбинацией из двух или более несвязанных типов (что может иметь смысл, когда все, но не более одного, являются типами интерфейсов). См. Ответ Lino для примера.

Ответ 2

Пример использования, о котором я думаю, может состоять в том, что некоторым нужен объект, который наследуется от 2 типов. Например. реализует 2 interfaces:

public class Foo {

    public <T extends Bar & Baz> Foo(T barAndBaz){
        barAndBaz.barMethod();
        barAndBaz.bazMethod();
    }
}

Хотя я никогда не использовал его в производстве.

Ответ 3

В примере показано, что U не играет никакой роли в конструкторе класса, так как он эффективно становится Object во время выполнения:

class Bar {
    <U> Bar(U you) {
        // Why!?
    }
}

Но скажем, что я хотел, чтобы мой конструктор принимал только те типы, которые расширяют какой-либо другой класс или интерфейс, как показано ниже:

class Foo<T extends Baz> {
    <U extends Bar> Foo(U u) {
        // I must be a Bar!
    }
}

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

Конечно, я никогда не использовал что-то подобное, и я никогда не видел его в использовании, но это возможно!

Ответ 4

Собственно, этот конструктор

class Bar {
    <U> Bar(U you) {
        // Why!?
    }
}

аналогичен общий метод. Было бы гораздо больше смысла, если бы у вас было несколько аргументов конструктора:

class Bar {
    <U> Bar(U you, U me) {
        // Why!?
    }
} 

Затем вы можете применить ограничение, чтобы они имели одинаковое время с компилятором. Не делая U общим для всего класса.

Ответ 5

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

public class Foo {
    Object o;

    public Foo(Object o) {
        this.o = o;
    }
}

... но, как прохождение пустой Object, если вы не делаете что-то умное, это имеет мало практического значения.

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

public class Foo<T extends Collection<?>> {
    T collection;
    public Foo(T collection) {
        this.collection = collection;
    }
}

Эффективно, это больше о гибкости, чем о чем-то революционном. Если вы хотите, чтобы гибкость проходила в определенной категории типов, тогда у вас есть возможность сделать это здесь. Если вы этого не сделаете, то со стандартными классами нет ничего плохого. Это просто для вашего удобства, и поскольку стирание стилей по-прежнему является вещью, несвязанный общий то же (и имеет ту же полезность), что и передача Object.