Избегайте приведения в родовую инфраструктуру MVP на основе фабрики [duplicate]

Команда

-v работает нормально, если для параметра <command> установлено значение параметра POSIX_BUILTINS, но может быть неудачно, если нет. (он работал для меня в течение многих лет, но в последнее время столкнулся с тем, где он не работал).

Я считаю следующее более отказоустойчивым:

test -x $(which <command>)

он проверяет на 3 вещи: путь, исполнение и разрешение.

560
задан Lii 5 April 2016 в 14:59
поделиться

9 ответов

tl; dr: «PECS» находится с точки зрения коллекции. Если вы только вытаскиваете предметы из общей коллекции, это производитель, и вы должны использовать extends; если вы загружаете только элементы, это потребитель, и вы должны использовать super. Если вы делаете оба с одной и той же коллекцией, вы не должны использовать либо extends, либо super.


Предположим, что у вас есть метод, который принимает в качестве параметра набор вещей, но вы хотите, чтобы он был более гибким, чем просто принятие Collection<Thing>.

Случай 1: вы хотите пройти коллекцию и делать вещи с каждым элементом. Затем список будет производителем, поэтому вы должны использовать Collection<? extends Thing>.

. Поводом является то, что Collection<? extends Thing> может содержать любой подтип Thing, и поэтому каждый элемент будет вести себя как Thing ] при выполнении операции. (Фактически вы не можете добавить что-либо к Collection<? extends Thing>, потому что во время выполнения вы не можете знать, какой подтип [] Thing содержится в коллекции.)

Случай 2: вы хотите добавьте вещи в коллекцию. Затем список - это потребитель, поэтому вы должны использовать Collection<? super Thing>.

. Здесь рассуждение состоит в том, что в отличие от Collection<? extends Thing>, Collection<? super Thing> всегда может удерживать Thing независимо от того, какой фактический параметризованный тип является. Здесь вам все равно, что уже есть в списке, если он позволит добавить Thing; это то, что гарантирует ? super Thing.

643
ответ дан Michael Myers 3 September 2018 в 16:41
поделиться

(добавление ответа, потому что примеров с универсальными символами Generics недостаточно)

       // Source 
       List<Integer> intList = Arrays.asList(1,2,3);
       List<Double> doubleList = Arrays.asList(2.78,3.14);
       List<Number> numList = Arrays.asList(1,2,2.78,3.14,5);

       // Destination
       List<Integer> intList2 = new ArrayList<>();
       List<Double> doublesList2 = new ArrayList<>();
       List<Number> numList2 = new ArrayList<>();

        // Works
        copyElements1(intList,intList2);         // from int to int
        copyElements1(doubleList,doublesList2);  // from double to double


     static <T> void copyElements1(Collection<T> src, Collection<T> dest) {
        for(T n : src){
            dest.add(n);
         }
      }


     // Let's try to copy intList to its supertype
     copyElements1(intList,numList2); // error, method signature just says "T"
                                      // and here the compiler is given 
                                      // two types: Integer and Number, 
                                      // so which one shall it be?

     // PECS to the rescue!
     copyElements2(intList,numList2);  // possible



    // copy Integer (? extends T) to its supertype (Number is super of Integer)
    private static <T> void copyElements2(Collection<? extends T> src, 
                                          Collection<? super T> dest) {
        for(T n : src){
            dest.add(n);
        }
    }
3
ответ дан Andrejs 3 September 2018 в 16:41
поделиться

Как я объясняю в мой ответ на другой вопрос, PECS - это мнемоническое устройство, созданное Джошем Блохом, чтобы помочь вспомнить производителя extends, Consumer super.

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

Когда параметризованный тип, передаваемый методу, будет потреблять экземпляры T (они будут переданы в он должен что-то сделать), ? super T следует использовать, потому что экземпляр T можно законно передать любому методу, который принимает некоторый супертип T. Например, Comparator<Number> можно использовать на Collection<Integer>. ? extends T не будет работать, потому что Comparator<Integer> не может работать на Collection<Number>.

Обратите внимание, что обычно вы должны использовать только ? extends T и ? super T для параметров какого-либо метода. Методы должны использовать T только как параметр типа для типичного типа возврата.

20
ответ дан Cody Gray 3 September 2018 в 16:41
поделиться

Принципы, лежащие в основе этого в информатике, названы в честь

  • Ковариация -? extends MyClass,
  • Контравариантность -? super MyClass и
  • Инвариантность / невариантность - MyClass

На рисунке ниже должна быть объяснена концепция.

Любезность фотографии: Андрей Тюкин

Covariance vs Contravariance [/g1]

447
ответ дан Community 3 September 2018 в 16:41
поделиться
public class Test {

    public class A {}

    public class B extends A {}

    public class C extends B {}

    public void testCoVariance(List<? extends B> myBlist) {
        B b = new B();
        C c = new C();
        myBlist.add(b); // does not compile
        myBlist.add(c); // does not compile
        A a = myBlist.get(0); 
    }

    public void testContraVariance(List<? super B> myBlist) {
        B b = new B();
        C c = new C();
        myBlist.add(b);
        myBlist.add(c);
        A a = myBlist.get(0); // does not compile
    }
}
26
ответ дан Gab 3 September 2018 в 16:41
поделиться

Запомните это:

Потребители едят ужин (супер); Производитель продлевает фабрику своего родителя

2
ответ дан Lonely Neuron 3 September 2018 в 16:41
поделиться

В двух словах легко запомнить PECS

  1. Используйте подстановочный символ <? extends T>, если вам нужно извлечь объект типа T из коллекции.
  2. Используйте кнопку <? super T>, если вам нужно поместить объекты типа T в коллекцию.
  3. Если вам нужно удовлетворить обе вещи, ну, не используйте подстановочный знак. Так просто, как это.
16
ответ дан Pradeep Kr Kaushal 3 September 2018 в 16:41
поделиться

PECS (производитель extends и потребитель super)

Мнемоника → принцип Get и Put.

Этот принцип гласит, что:

  • Используйте расширенный подстановочный знак, когда вы получаете только значения из структуры.
  • Используйте суперсимвол, когда вы только Поместите значения в структуру.
  • И не используйте подстановочный знак, когда вы оба получаете и ставите.

В Java параметры и параметры типового типа не поддерживают наследование следующим образом.

class Super {
    void testCoVariance(Object parameter){} // method Consumes the Object
    Object testContraVariance(){ return null;} //method Produces the Object
}

class Sub extends Super {
    @Override
    void testCoVariance(String parameter){} //doesn't support eventhough String is subtype of Object

    @Override
    String testContraVariance(){ return null;} //compiles successfully i.e. return type is don't care 
}

Принцип подстановки Лискова: Массивы являются ковариантными (небезопасными), но Generics не являются, то есть инвариантными (безопасными). Принцип подстановки не работает с параметризованными типами, что означает, что это незаконно писать. Ковариант просто означает, что X является подтипом Y, тогда X[] также будет подтипом Y[].

Object name= new String("prem"); //works
List<Number> numbers = new ArrayList<Integer>();//gets compile time error

Integer[] myInts = {1,2,3,4};
Number[] myNumber = myInts;
myNumber[0] = 3.14; //attempt of heap pollution i.e. at runtime gets java.lang.ArrayStoreException: java.lang.Double(we can fool compiler but not run-time)

List<String> list=new ArrayList<>();
list.add("prem");
List<Object> listObject=list; //Type mismatch: cannot convert from List<String> to List<Object> at Compiletime  

больше примеров

ограниченный (т. е. заголовок к чему-либо) подстановочный знак: Есть 3 разных варианта подстановочных знаков:

  • In-variance / Non-variance: ? или ? extends Object - неограниченный подстановочный знак. Он обозначает семью всех типов. Использовать, когда вы оба получаете и ставите.
  • Соотношение: ? extends T (семейство всех типов, которые являются подтипами T) - подстановочный знак с верхней границей. T является самым верхним классом в иерархии наследования. Используйте подстановочный знак extends, когда вы получаете только значения из структуры.
  • Contra-variance: ? super T (семейство всех типов, которые являются супертипами T) - подстановочный знак с нижней границей. T является самым низким классом в иерархии наследования. Используйте подстановочный символ super, если вы только поместите значения в структуру.

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

class Shape { void draw() {}}

class Circle extends Shape {void draw() {}}

class Square extends Shape {void draw() {}}

class Rectangle extends Shape {void draw() {}}

public class TestContraVariance {
 /*
   * Example for an upper bound wildcard (Get values i.e Producer `extends`)
   * 
   * */  

    public void testCoVariance(List<? extends Shape> list) {
        list.add(new Shape()); // Error:  is not applicable for the arguments (Shape) i.e. inheritance is not supporting
        list.add(new Circle()); // Error:  is not applicable for the arguments (Circle) i.e. inheritance is not supporting
        list.add(new Square()); // Error:  is not applicable for the arguments (Square) i.e. inheritance is not supporting
        list.add(new Rectangle()); // Error:  is not applicable for the arguments (Rectangle) i.e. inheritance is not supporting
        Shape shape= list.get(0);//compiles so list act as produces only

        /*You can't add a Shape,Circle,Square,Rectangle to a List<? extends Shape> 
         * You can get an object and know that it will be an Shape
         */         
    }
      /* 
* Example for  a lower bound wildcard (Put values i.e Consumer`super`)
* */
    public void testContraVariance(List<? super Shape> list) {
        list.add(new Shape());//compiles i.e. inheritance is supporting
        list.add(new Circle());//compiles i.e. inheritance is  supporting
        list.add(new Square());//compiles i.e. inheritance is supporting
        list.add(new Rectangle());//compiles i.e. inheritance is supporting
        Shape shape= list.get(0); // Error: Type mismatch, so list acts only as consumer
        Object object= list.get(0); // gets an object, but we don't know what kind of Object it is.

        /*You can add a Shape,Circle,Square,Rectangle to a List<? extends Shape> 
        * You can't get an Shape(but can get Object) and don't know what kind of Shape it is.
        */  
    }
}

generics и примеры

25
ответ дан Premraj 3 September 2018 в 16:41
поделиться

PECS (сокращение от «Производитель extends и Consumer super») объясняется: принципом «Get and Put»

«Get And Put» (из Java Generics and Collections)

Указывает, что

  1. использует расширенный подстановочный знак, когда вы получаете только значения из структуры
  2. , используя суперсимвол, когда вы добавляете значения только в структуру
  3. и не использовать подстановочный знак, когда вы оба получаете и ставите.

Давайте рассмотрим его на примере:

1. For Extends Wildcard (получить значения, т. Е. Producer extends)

Вот метод, который берет набор чисел, преобразует каждый в double и суммирует их вверх

public static double sum(Collection<? extends Number> nums) {
   double s = 0.0;
   for (Number num : nums) 
      s += num.doubleValue();
   return s;
}

Назовем метод:

List<Integer>ints = Arrays.asList(1,2,3);
assert sum(ints) == 6.0;
List<Double>doubles = Arrays.asList(2.78,3.14);
assert sum(doubles) == 5.92;
List<Number>nums = Arrays.<Number>asList(1,2,2.78,3.14);
assert sum(nums) == 8.92;

Поскольку метод sum() использует extends, все следующие вызовы являются законными. Первые два вызова не были бы законными, если бы расширения не использовались.

ИСКЛЮЧЕНИЕ : вы не можете помещать что-либо в тип, объявленный с помощью подстановочного знака extends, за исключением значения null, который относится к каждому ссылочному типу:

List<Integer> ints = new ArrayList<Integer>();
ints.add(1);
ints.add(2);
List<? extends Number> nums = ints;
nums.add(null);  // ok
assert nums.toString().equals("[1, 2, null]");

2. Для Super Wildcard (put values ​​ie Consumer super)

Вот метод, который принимает набор чисел и int n, и помещает первые n целые числа, начиная с нуля, в сбор:

public static void count(Collection<? super Integer> ints, int n) {
    for (int i = 0; i < n; i++) ints.add(i);
}

Давайте назовем метод:

List<Integer>ints = new ArrayList<Integer>();
count(ints, 5);
assert ints.toString().equals("[0, 1, 2, 3, 4]");
List<Number>nums = new ArrayList<Number>();
count(nums, 5); nums.add(5.0);
assert nums.toString().equals("[0, 1, 2, 3, 4, 5.0]");
List<Object>objs = new ArrayList<Object>();
count(objs, 5); objs.add("five");
assert objs.toString().equals("[0, 1, 2, 3, 4, five]");

Поскольку метод count() использует super, все следующие звонки законны: последние два вызова не были бы законными, если бы супер не использовался.

ИСКЛЮЧЕНИЕ : вы не можете получить что-либо из типа, объявленного с помощью super за исключением значения типа Object, которое является супертипом каждого ссылочного типа:

List<Object> objs = Arrays.<Object>asList(1,"two");
List<? super Integer> ints = objs;
String str = "";
for (Object obj : ints) str += obj.toString();
assert str.equals("1two");

3. Когда оба Get и Put, не используйте wildcard

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

public static double sumCount(Collection<Number> nums, int n) {
   count(nums, n);
   return sum(nums);
}
130
ответ дан Radiodef 3 September 2018 в 16:41
поделиться
Другие вопросы по тегам:

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