Что Список <?> Означает в дженериках Java? - PullRequest
39 голосов
/ 04 декабря 2009

Что означает List<?>, означает ли это просто список объектов неопределенного типа?

Поиск по строке в Google <?> ничего полезного не возвращает (:

Ответы [ 8 ]

41 голосов
/ 04 декабря 2009

Как сказал Том, ?, или неограниченный подстановочный знак, означает, что тип объекта не указан. Это может быть неизвестно, может быть предназначено для нескольких возможных значений или может быть просто несущественным. Ваш пример List<?> произносится как «Список неизвестных». Это удобно, потому что это гибко, но есть и некоторые подводные камни, потому что вы не можете засунуть случайные объекты и вытянуть их из групп неизвестных с полной безнаказанностью.

Ресурсы:

  • Подстановочные знаки обсуждаются здесь в руководстве по Java.
  • Есть хорошее - если многословно - учебное пособие по дженерикам в целом от Angelika Langer, доступное здесь .
  • И еще один хороший обзор здесь (PDF) Гилада Брача; проверьте страницы 5-7.
  • Наконец, если вы можете получить в руки Effective Java Джоша Блоха, у него есть отличный раздел об обобщениях и случаях, когда вы можете, не можете, должны и не должны использовать подстановочные знаки (глава 5, стр. 109-146 во втором издании).

Кстати, ваш поиск в Google не удался, потому что Google не использует специальные символы:

За некоторыми исключениями пунктуация игнорируется (то есть вы не можете искать @ # $% ^ & * () = + [] \ и другие специальные символы).

- Страница справки Google

(РЕДАКТИРОВАТЬ: Должно быть, я очень устал, когда писал вчера вечером. Очистил форматирование / добавил немного информации.)

32 голосов
/ 04 декабря 2009

Ключевое слово, которое вам нужно для получения дополнительной информации: Подстановочные знаки

5 голосов
/ 30 января 2017

Чтобы ответить на этот вопрос, мне нужно объяснить неограниченные символы и ограниченные символы.
Содержание этого поста было собрано из документации Java.

1. Неограниченные символы

Неограниченный тип подстановочного знака указывается с использованием подстановочного знака (?), например, List<?>. Это называется списком неизвестного типа. Существует два сценария, в которых неограниченный подстановочный знак является полезным подходом:

  • Если вы пишете метод, который может быть реализован с использованием функций, предоставляемых в классе Object.

  • Когда код использует методы в универсальном классе, которые не зависят от параметра типа. Например, List.size или List.clear. На самом деле, Class<?> используется так часто, потому что большинство методов в Class<T> не зависят от T.

2. Ограниченные подстановочные знаки

Рассмотрим простое приложение для рисования, которое может рисовать такие фигуры, как прямоугольники и круги. Чтобы представить эти фигуры в программе, вы можете определить иерархию классов, например:

public abstract class Shape {
    public abstract void draw(Canvas c);
}

public class Circle extends Shape {
    private int x, y, radius;
    public void draw(Canvas c) {
        ...
    }
}

public class Rectangle extends Shape {
    private int x, y, width, height;
    public void draw(Canvas c) {
        ...
    }
}

Эти классы могут быть нарисованы на холсте:

public class Canvas {
    public void draw(Shape s) {
        s.draw(this);
   }
}

Любой рисунок обычно содержит несколько фигур. Предполагая, что они представлены в виде списка, было бы удобно иметь метод в Canvas, который их всех рисует:

public void drawAll(List<Shape> shapes) {
    for (Shape s: shapes) {
        s.draw(this);
   }
}

Теперь правила типа говорят, что drawAll() можно вызывать только в списках точно Shape: его нельзя, например, вызывать для List<Circle>. Это прискорбно, так как все, что делает метод - это читает фигуры из списка, поэтому его можно также вызывать для List<Circle>. Что нам действительно нужно, так это чтобы метод принимал список любой формы: public void drawAll (Список фигур) { ... } Здесь есть небольшое, но очень важное отличие: мы заменили тип List<Shape> на List<? extends Shape>. Теперь drawAll() будет принимать списки любого подкласса Shape, поэтому теперь мы можем вызвать его на List<Circle>, если захотим.

List<? extends Shape> является примером ограниченного символа подстановки. ? обозначает неизвестный тип, однако в этом случае мы знаем, что этот неизвестный тип на самом деле является подтипом Shape. (Примечание: это может быть сама форма или некоторый подкласс; ей не нужно буквально расширять форму.) Мы говорим, что форма - это верхняя граница подстановочного знака.

Аналогично, синтаксис ? super T, который является ограниченным подстановочным знаком, обозначает неизвестный тип, который является супертипом T. A ArrayedHeap280<? super Integer>, например, включает в себя ArrayedHeap280<Integer>, ArrayedHeap280<Number> и ArrayedHeap280<Object>. Как вы можете видеть в документации Java для класса Integer , Integer является подклассом Number, который, в свою очередь, является подклассом Object.

4 голосов
/ 04 декабря 2009

Похоже, вам следует поискать документацию по дженерикам Java.

List<?> означает, что это объект, основанный на неопределенном типе. Эта спецификация создается, когда создается экземпляр класса.

Например:

List<String> listOfStrings = new ArrayList<String>();

- список объектов String.

3 голосов
/ 04 декабря 2009

List - это интерфейс, который вы можете реализовать самостоятельно, а также реализованный в некоторых коллекциях Java, например Vector.

Вы можете предоставить информацию о наборе во время компиляции, используя угловые скобки. Самый общий тип будет Object, который будет List<Object>. <?>, который вы видите, указывает список некоторого подкласса Object или Object. Это все равно что сказать List<? extends Object>, или List<? extends Foo>, где List содержит объекты некоторого подкласса Foo или объекты самого Foo.

Вы не можете создать экземпляр List; это интерфейс, а не реализация.

2 голосов
/ 04 декабря 2009

List<?> означает List<? extends Object>, поэтому в Collection<E> вы найдете containsAll(Collection<?> c), что позволяет писать

List<Object> objs = Arrays.<Object>asList("one",2,3.14,4);
List<Integer> ints = Arrays.asList(2,4);
assert objs.containsAll(ints);//true
0 голосов
/ 04 декабря 2009

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

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

chk dis pdf

0 голосов
/ 04 декабря 2009

Вероятно, вы смотрите на шаблон List класса. Вы можете создать список строк с помощью List<String> myList = new MyList<String>(); в качестве примера. Проверьте документацию для всех поддерживаемых типов. Он должен поддерживать любой тип объекта, но если есть функция сортировки, вы должны предоставить некоторые функции сравнения.

Обратите внимание, что в приведенном выше примере MyList - это конкретный класс, который реализует интерфейс List в Java. Это может быть ArrayList.

EDIT: Я принял List как конкретный класс по ошибке. Исправлена ​​ошибка выше. Спасибо Джон.

...