Передача списка объектов, которые реализуют определенный интерфейс для метода [duplicate]

Вы можете использовать функции empty () и isset (). Если вы хотите, чтобы он работал с разными файлами, просто измените action='yourphp.php' на html, который я вам даю, и store the PHP script на этот файл yourphp.php. Также вам нужно изменить index.html на index.php, чтобы активировать функции PHP.

PHP

<?php

    error_reporting(0);
    $name = $_POST['name'];
    $email = $_POST['email'];
    $message = $_POST['message'];
    $from = 'From: yoursite.com'; 
    $to = 'contact@yoursite.com'; 
    $subject = 'Customer Inquiry';
    $body = "From: $name\n E-Mail: $email\n Message:\n $message";


    if ($_POST['submit']){
                if (!(empty($_POST['name']))) {
                        if (!(empty($_POST['email']))){
                            if (!(empty($_POST['message']))){
                                mail ($to, $subject, $body, $from);
                                echo '<p>Your message has been sent!</p>';
                            }else{
                                echo '<p>Fill your message please.</p>';}
                        }else {
                            echo '<p>Fill your email please.</p>';}
                }else{
                    echo '<p>Fill your name please.</p>';}              
    }else{
            echo '<p>Fill the form.</p>';}
?>

HTML

<html>
    <form method="post" action="?">
        <table>
            <tr><td>Name</td><td><input type='text' name='name' id='name'/></td></tr>
            <tr><td>Email</td><td><input type='text' name='email' id='email'/></td></tr>
            <tr><td>Message</td><td><input type='text' name='message' id='message'/></td></tr>
            <tr><td></td><td><input type='submit' name='submit' id='submit'/></td></tr>
        </table>
    </form>
</html>

С наилучшими пожеланиями!

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

11 ответов

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.

640
ответ дан Michael Myers 21 August 2018 в 08:41
поделиться
  • 1
    Я всегда стараюсь думать об этом следующим образом: A производитель позволяет создавать нечто более конкретное, поэтому extends , потребитель разрешен принять что-то более общее, следовательно super . – Feuermurmel 7 May 2013 в 14:11
  • 2
    Еще один способ запомнить разницу между производителем и потребителем - это думать о подписи метода. Если у вас есть метод doSomethingWithList(List list), вы потребляете список, поэтому нам потребуется ковариация / extends (или инвариантный список). С другой стороны, если ваш метод List doSomethingProvidingList, вы производят список и нуждаетесь в контравариантности / супер (или в инвариантном списке). – Raman 24 January 2014 в 21:20
  • 3
    @MichaelMyers: Почему мы не можем просто использовать параметризованный тип для обоих этих случаев? Есть ли какое-либо конкретное преимущество использования подстановочных знаков здесь, или это просто средство повышения удобочитаемости, аналогичное, например, использованию ссылок на const в качестве параметров метода в C ++, чтобы показать, что метод не изменяет аргументы? – Chatterjee 24 May 2014 в 07:27
  • 4
    @Raman, я думаю, вы просто смутили его. В doSthWithList (вы можете иметь List & lt ;? super Thing & gt;), так как вы являетесь потребителем, вы можете использовать супер (помните, CS). Однако это List & lt ;? расширяет Thing & gt; getList (), поскольку вам разрешено возвращать что-то более конкретное при создании (PE). – masterxilo 27 May 2014 в 20:08
  • 5
    @EricZhang: Когда вы добавляете в коллекцию, не имеет значения, является ли коллекция итерируемой. – Michael Myers♦ 1 June 2017 в 00:20

(добавление ответа, потому что примеров с универсальными символами 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 21 August 2018 в 08: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 только как параметр типа для типичного типа возврата.

18
ответ дан Cody Gray 21 August 2018 в 08:41
поделиться

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

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

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

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

Covariance vs Contravariance [/g1]

444
ответ дан Community 21 August 2018 в 08:41
поделиться
  • 1
    Всем привет. Я Андрей Тюкин, я просто хотел подтвердить, что аноопии и amp; ДаоВен связался со мной и получил мое разрешение на использование эскиза, оно лицензировано в соответствии с (CC) -BY-SA. Thx @ Anoop за вторую жизнь ^^ @Brian Agnew: (на «несколько голосов»): Это потому, что это эскиз для Scala, он использует синтаксис Scala и предполагает отклонение на уровне объявления, что сильно отличается от странности Java разброс на основе кода ... Возможно, мне следует написать более подробный ответ, который четко показывает, как этот эскиз применяется к Java ... – Andrey Tyukin 16 June 2014 в 00:11
  • 2
    Это одно из самых простых и ясных объяснений ковариации и контравариантности, которые я когда-либо нашел! – cs4r 1 May 2017 в 12:35
  • 3
    @ Андрю Тюкин Привет, я тоже хочу использовать этот образ. Как я могу связаться с вами? – slouc 2 June 2017 в 08:06
  • 4
    Если у вас есть какие-либо вопросы по поводу этой иллюстрации, мы можем обсудить их в чате: chat.stackoverflow.com/rooms/145734/… – Andrey Tyukin 2 June 2017 в 17:16
  • 5
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 21 August 2018 в 08:41
поделиться
  • 1
    Итак, "? расширяет B & quot; следует интерпретировать как "? B продолжается ". Это то, что B распространяется так, что будет включать все суперклассы B до Object, исключая B. Спасибо за код! – Saurabh Patil 30 May 2016 в 03:47
  • 2
    @SaurabhPatil Нет, ? extends B означает B и все, что простирается B. – asgs 28 September 2016 в 06:16

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

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

2
ответ дан Lonely Neuron 21 August 2018 в 08:41
поделиться

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

  1. Используйте подстановочный символ <? extends T>, если вам нужно извлечь объект типа T из коллекции.
  2. Используйте кнопку <? super T>, если вам нужно поместить объекты типа T в коллекцию.
  3. Если вам нужно удовлетворить обе вещи, ну, не используйте подстановочный знак. Так просто, как это.
14
ответ дан Pradeep Kr Kaushal 21 August 2018 в 08: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 и примеры

24
ответ дан Premraj 21 August 2018 в 08:41
поделиться
  • 1
    Эй, я просто хотел узнать, что вы имели в виду с последним чувством: «Если вы думаете, что моя аналогия неверна, пожалуйста, обновите». Вы имеете в виду, если это этически неправильно (что субъективно), или если оно неверно в контексте программирования (что объективно: нет, это не так)? Я хотел бы заменить его более нейтральным примером, который универсально приемлем независимо от культурных норм и этических убеждений; Если с тобой все в порядке. – Lonely Neuron 29 April 2018 в 06:12

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);
}
126
ответ дан Radiodef 21 August 2018 в 08:41
поделиться
0
ответ дан Ali Yeganeh 1 November 2018 в 03:21
поделиться
3
ответ дан Daniel 1 November 2018 в 03:21
поделиться
Другие вопросы по тегам:

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