Почему функция не принимать ссылку на метод из подкласса? - PullRequest
0 голосов
/ 05 мая 2020

Допустим, у меня есть интерфейс Animal с методом String getRace() и подклассом Dog. Я держу некоторых животных в List<Animal>.

Теперь, если бы я хотел отсортировать этот список и передать Function<Animal, String> в метод, чтобы использовать его вместе с Comparator.comparing(...), это сработало бы. Однако, если я ссылаюсь на функцию из Dog для передачи в качестве аргумента, компилятор выдает следующую ошибку:

Тип Zoo.Dog не определяет применимый getRace (Zoo.Animal) здесь.

даже если это подкласс Animal и определяет эту функцию.

Вот код:

import java.util.*;
import java.util.function.*;
import java.util.stream.*;

public class Zoo {

    public interface Animal {

        public String getRace();

    }

    public class Dog implements Animal {

        public String getRace() {
            return "Some race";
        }

    }

    private List<Animal> animals = Arrays.asList(new Animal[] {});

    public void sort(Function<Animal, String> function) {
        animals = animals.stream().sorted(Comparator.comparing(function)).collect(Collectors.toList());
    }

    public static void main(String[] args) {
        Zoo zoo = new Zoo();

        // Error: "The type Zoo.Dog does not define getRace(Zoo.Animal) that is applicable here"
        zoo.sort(Dog::getRace);
    }

}

Почему это?

Я нашел этот вопрос , но в этом примере классы никак не связаны друг с другом.

Ответы [ 2 ]

1 голос
/ 05 мая 2020

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

public static void main (String[] args) {
    Zoo zoo = new Zoo();
    zoo.sort(Animal::getRace);
}

Причина проста:

Чтобы отсортировать список Animal с использованием Comperator, он должен быть Comperator<Animal>. Это означает, что функция, которую вы передаете в Comperator.comparing, должна быть Function<? super Animal,? extends Comperable>. Это неверно для Function<Dog, String>, однако это верно для Function<Animal, String> и Function<Object, String>.

Вы правильно определяете свой .sort(), чтобы взять Function<Animal, String>, но вы передаете функцию-член Dog - это, по сути, функция Dog -> String или Function<Dog,String> в функциональных интерфейсах.


В менее технических терминах: да, Dog может делать все, что Animal. Однако это не так - Dog может иметь функцию, которая есть не у всех животных. Следовательно, недопустимо использовать Function<Dog,?> вместо Function<Animal,?>, но все будет нормально.

1 голос
/ 05 мая 2020

Dog::getRace ожидает экземпляр Dog, но animals.stream() предоставляет Animal экземпляров.

Что должно работать, я думаю, поскольку Dog реализует Animal и getRace объявлено в Animal:

    zoo.sort(Animal::getRace);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...