Почему я не могу использовать аргумент типа в параметре типа с несколькими границами?

NullPointerException s - исключения, возникающие при попытке использовать ссылку, которая указывает на отсутствие местоположения в памяти (null), как если бы она ссылалась на объект. Вызов метода по нулевой ссылке или попытка получить доступ к полю нулевой ссылки вызовет функцию NullPointerException. Они наиболее распространены, но другие способы перечислены на странице NullPointerException javadoc.

Вероятно, самый быстрый пример кода, который я мог бы придумать для иллюстрации NullPointerException, be:

public class Example {

    public static void main(String[] args) {
        Object obj = null;
        obj.hashCode();
    }

}

В первой строке внутри main я явно устанавливаю ссылку Object obj равной null. Это означает, что у меня есть ссылка, но она не указывает на какой-либо объект. После этого я пытаюсь обработать ссылку так, как если бы она указывала на объект, вызывая метод на нем. Это приводит к NullPointerException, потому что нет кода для выполнения в местоположении, на которое указывает ссылка.

(Это техничность, но я думаю, что она упоминает: ссылка, которая указывает на null, равна 't то же, что и указатель C, указывающий на недопустимую ячейку памяти. Нулевой указатель буквально не указывает на в любом месте , который отличается от указаний на местоположение, которое оказывается недопустимым.)

51
задан Duncan Jones 28 September 2014 в 22:47
поделиться

4 ответа

Я также не уверен, почему ограничение там. Вы могли попытаться послать дружественное электронное письмо разработчикам Java 5 Дженериков (в основном Gilad Bracha и Neal Gafter).

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

И почему этот случай даже поддерживался? Ответ - то, что несколько границ позволяют Вам управлять стиранием, которое позволяет поддерживать совместимость на уровне двоичных кодов когда generifying существующие классы. Как объяснено в разделе 17.4 из книга Naftalin и Wadler, max метод логически имел бы следующую подпись:

public static <T extends Comparable<? super T>> T max(Collection<? extends T> coll)

Однако это стирается к:

public static Comparable max(Collection coll)

, Который не соответствует исторической подписи max и заставляет старые клиенты повреждаться. С несколькими границами только связанное крайнее левое рассматривают для стирания, поэтому если max дан следующую подпись:

public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll)

Тогда стирание его подписи становится:

public static Object max(Collection coll)

, Который равен подписи max перед Дженериками.

кажется вероятным, что разработчики Java только заботились об этом простом случае и ограниченный другом (более усовершенствованный), использование пересечения вводит, потому что они были просто не уверены в сложности, что это могло бы принести. Таким образом, причиной этого проектного решения не должны быть возможные проблемы безопасности (как вопрос предполагает).

[еще 1119] обсуждение перекрестных типов и ограничений дженериков в предстоящая бумага OOPSLA .

28
ответ дан Marco13 7 November 2019 в 10:21
поделиться

Две возможных причины для объявления вне закона этого:

  1. Сложность. ошибка Sun 4899305 предполагает, что связанное, содержащее параметр типа плюс дополнительные параметризованные типы, допускало бы еще более сложные взаимно рекурсивные типы, чем, уже существуют. Короче говоря, ответ Bruno .

  2. возможность определения недопустимых типов. А именно, расширение универсального интерфейса дважды с различными параметрами . Я не могу придумать неизобретенный пример, но:

    /** Contains a Comparator<String> that also implements the given type T. */
    class StringComparatorHolder<T, C extends T & Comparator<String>> {
      private final C comparator;
      // ...
    }
     
    void foo(StringComparatorHolder<Comparator<Integer>, ?> holder) { ... }

Теперь holder.comparator Comparator<Integer> и Comparator<String>. Мне точно не ясно, сколько неприятностей это доставило бы компилятору, но это ясно не хорошо. Предположим в особенности, что Comparator имел метод как это:

void sort(List<? extends T> list);

Наш Comparator<Integer> / Comparator<String> гибрид теперь имеет два метода с тем же стиранием:

void sort(List<? extends Integer> list);
void sort(List<? extends String> list);

Это для этих видов причин, что Вы не можете определить такой тип непосредственно:

<T extends Comparator<Integer> & Comparator<String>> void bar() { ... }
java.util.Comparator cannot be inherited with different arguments:
    <java.lang.Integer> and <java.lang.String>

С тех пор <A extends I & Adapter<E>> позволяет Вам делать то же самое косвенно, оно отсутствует, также.

14
ответ дан Community 7 November 2019 в 10:21
поделиться

Вот другая кавычка от JLS:

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

, Что точно является теми неловкими положениями, я не знаю.

11
ответ дан Jan Soltis 7 November 2019 в 10:21
поделиться

Это, вероятно, не отвечает на основной вопрос, но просто хочет указать, что спецификация однозначно запрещает его. Поиск Google сообщения об ошибке взял меня к эта запись в блоге , который дальнейшие точки к jls 4.4:

связанное состоит или из переменной типа, или из класс или интерфейсный тип T, возможно сопровождаемый дальнейшим интерфейсом, вводят I1..., В.

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

, Почему ограничение? Я понятия не имею.

2
ответ дан Bill the Lizard 7 November 2019 в 10:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: