Коллекции Java с использованием подстановочных знаков - PullRequest
9 голосов
/ 16 сентября 2008
public static void main(String[] args) {

    List<? extends Object> mylist = new ArrayList<Object>();

    mylist.add("Java"); // compile error

}

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

Ответы [ 7 ]

5 голосов
/ 16 сентября 2008

Допустим, у вас есть интерфейс и два класса:

interface IResult {}
class AResult implements IResult {}
class BResult implements IResult {}

Тогда у вас есть классы, которые возвращают список в результате:

interface ITest<T extends IResult> {
  List<T> getResult();
}

class ATest implements ITest<AResult> {
  // look, overridden!
  List<AResult> getResult();
}

class BTest implements ITest<BResult> {
  // overridden again!
  List<BResult> getResult();
}

Это хорошее решение, когда вам нужны «ковариантные возвраты», но вы возвращаете коллекции вместо своих собственных объектов. Большой плюс в том, что вам не нужно создавать объекты при использовании ATest и BTest независимо от интерфейса ITest. Однако при использовании интерфейса ITest вы не можете ничего добавить в возвращенный список - так как вы не можете определить, какие типы объектов этот список действительно содержит! Если это будет разрешено, вы сможете добавить BResult в список (возвращается как List <? Extends T>), что не имеет никакого смысла.

Итак, вы должны запомнить это: Список <? extends X> определяет список, который можно легко переопределить, но который доступен только для чтения.

5 голосов
/ 16 сентября 2008

В своей книге «Эффективная Java» (второе издание) Джошуа Блох объясняет то, что он называет принципом производитель / потребитель для использования дженериков. Объяснение Джоша должно сказать вам, почему ваш пример не работает (компилировать) ...

Глава 5 (Generics) находится в свободном доступе здесь: http://java.sun.com/docs/books/effective/generics.pdf

Более подробная информация о книге (и авторе) доступна: http://java.sun.com/docs/books/effective/

1 голос
/ 16 сентября 2008

Смысл ограниченных групповых типов заключается в их использовании в сигнатурах методов для повышения гибкости API. Если, например, вы реализуете универсальный Stack<E>, вы можете предоставить метод для помещения нескольких элементов в стек, например:

public void pushAll(Iterable<? extends E> elements) {
    for(E element : elements){
       push(e);
    }
}

По сравнению с pushAll(Iterable<E> elements) подписью без подстановочного знака, это имеет то преимущество, что позволяет передавать в коллекцию наборы подтипов E - обычно это не допускается, потому что Iterable<String> несколько нелогично , не подкласс Iterable<Object>.

1 голос
/ 16 сентября 2008

При использовании java-обобщений с использованием подстановочных знаков вы можете использовать приведенную выше декларацию при условии, что вы только собираетесь читать из нее.

Вы не можете добавлять / записывать в него, потому что все универсальные типы должны быть удалены во время компиляции, и во время компиляции нет способа, которым компилятор знает, что List - это только строки, (это может быть любой объект включая строки!)

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

0 голосов
/ 25 марта 2016

Обобщения Java: подстановочные знаки в коллекциях

  1. продолжается
  2. супер

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

Теперь предположим, что у вас есть абстрактный класс, и у вас есть абстрактный метод paintObject ().

Now you want to use different type of collection in every child class.

Ниже приведен метод AbstractMain.

Вот шаги, которые мы предприняли для этого абстрактного метода Main

1. Мы создали абстрактный класс

2. В параметре у нас есть определение T (вы можете использовать любой символ) - В этом случае любой класс, реализующий этот метод, может использовать любой тип класса. ех. Класс может реализовывать метод как public void paintObject (объект ArrayList) или public void paintObject (объект HashSet)

3. И мы также использовали E extends MainColorTO - В этом случае E расширяет MainColorTo - Это ясно означает, какой класс вы хотите использовать, который должен быть подклассом MainColorTo

4. Мы должны определить абстрактный метод с именем paintObject (T object, E objectTO) - Теперь здесь, в зависимости от того, какой класс реализует метод, метод может использовать любой класс по первому аргументу, а по второму параметру этот метод должен использовать тип MainColorTO

public abstract class AbstractMain<T,E extends MainColorTO> {
      public abstract void paintObject(T Object,E TO);  
}

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

public class MainColorTO {  
     public void paintColor(){
           System.out.println("Paint Color........");
     } 
  }

public class RedTO extends MainColorTO {
   @Override
   public void paintColor() {
   System.out.println("RedTO......");
 }
}
public class WhiteTO extends MainColorTO {
   @Override
   public void paintColor() {
     System.out.println("White TO......");
   }
 }

Теперь мы возьмем два примера.

1.PaintHome.java

public class PaintHome extends AbstractMain<ArrayList, RedTO> {
    @Override
    public void paintObject(ArrayList arrayList,RedTO red) {
        System.out.println(arrayList);

    }
 }

Теперь выше в PaintHome.java вы можете проверить, что мы использовали ArrayList в первом аргументе (как мы можем взять любой класс), а во втором аргументе мы использовали RedTO (который расширяет MainColorTO)

2.PaintCar.java

public class PaintCar extends AbstractMain<HashSet, WhiteTO>{
    @Override
    public void paintObject(HashSet Object,WhiteTO white) {
        System.out.println(Object);

    }
 }

Теперь выше в PaintCar.java вы можете проверить, что мы использовали HashSet в первом аргументе (как мы можем принять любой класс), а во втором аргументе мы использовали WhiteTO (который расширяет MainColorTO)

Понять, чтобы запомнить Вы не можете использовать супер ключевое слово на уровне класса, вы можете использовать только ключевое слово extends при определении уровня класса

public abstract class AbstractMain<P,E super MainColorTO> {

    public abstract void paintObject(P Object,E TO);

}

Приведенный выше код выдаст вам ошибку компилятора.

0 голосов
/ 16 сентября 2008

List<? extends Object>, что совпадает с List<?>, выполняет обобщение всех типов List<String>, List<Number>, List<Object> и т. Д. (Поэтому все типы с правильным типом вместо ?). Значения всех этих типов могут быть присвоены переменной типа List<?> (чем она отличается от List<Object>!).

Как правило, вы не можете добавить строку в такой список. Однако вы можете прочитать Object из списка и добавить к нему null. Вы также можете рассчитать длину списка и т. Д. Это операции, которые гарантированно работают для каждого из этих типов.

Хорошее введение в подстановочные знаки см. В статье Добавление подстановочных знаков в язык программирования Java . Это академическая статья, но все еще очень доступная.

0 голосов
/ 16 сентября 2008

Это работает:

List<? super Object> mylist = new ArrayList<Object>();
mylist.add("Java"); // no compile error

Из О'Рейли Java Generics :

Принцип Get и Put: используйте подстановочный знак расширения, когда вы только получаете значения нашей структуры, используйте супер подстановочный знак, когда вы только помещаете значения в структуру, и не используйте подстановочный знак, который вы оба получаете и ставите. 1009 *

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...