为什么 `Function` 不接受从子类中的方法引用?

huangapple go评论70阅读模式
英文:

Why does Function<Interface, R> not accept a method reference from a subclass?

问题

以下是翻译好的内容:

假设我有一个接口 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();
        
        // 错误:"类型 Zoo.Dog 在这里没有定义适用的 getRace(Zoo.Animal)"
        zoo.sort(Dog::getRace);
    }

}

为什么会这样呢?

我在这个问题中找到了类似的情况,但在那个示例中,这些类之间没有关联。

英文:

Let's say I have an interface Animal with the method String getRace() and a subclass Dog. I keep some animals in a List&lt;Animal&gt;.

Now if I wanted to sort that list and passed a Function&lt;Animal, String&gt; into the method to use it together with Comparator.comparing(...) that would work fine. However, if I reference a function from Dog to pass as an argument, the compiler throws the following error:

> The type Zoo.Dog does not define getRace(Zoo.Animal) that is applicable here.

even though it's a subclass of Animal and does define that function.

Here's the code:

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 &quot;Some race&quot;;
		}

	}

	private List&lt;Animal&gt; animals = Arrays.asList(new Animal[] {});

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

	public static void main(String[] args) {
		Zoo zoo = new Zoo();
		
		// Error: &quot;The type Zoo.Dog does not define getRace(Zoo.Animal) that is applicable here&quot;
		zoo.sort(Dog::getRace);
	}

}

Why is that?

I've found this question, but in that example the classes are in no relation to each other.

答案1

得分: 1

Dog::getRace 需要一个 Dog 实例,但是 animals.stream() 提供了 Animal 实例。

我猜应该能工作,因为 Dog 实现了 Animal,而且 getRaceAnimal 中声明:

    zoo.sort(Animal::getRace);
英文:

Dog::getRace expects a Dog instance, but animals.stream() provides Animal instances.

What should work, I guess, since Dog implements Animal and getRace is declared in Animal:

    zoo.sort(Animal::getRace);

答案2

得分: 1

这是有效的代码:

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

原因很简单:

要使用ComparatorAnimal的列表进行排序,它需要是一个Comparator<Animal>。这意味着您传递给Comparator.comparing的函数需要是一个Function<? super Animal, ? extends Comparable>。然而,对于Function<Dog, String>来说并不成立,但对于Function<Animal, String>Function<Object, String>来说是成立的。

您正确地定义了.sort()来接受Function<Animal, String>,但您传递了一个Dog的成员函数 - 实质上是一个函数Dog -> String,或者在函数式接口中是Function<Dog, String>


用不太技术性的说法:是的,Dog可以做的事情Animal也能做。然而,反过来却不成立 - Dog可以有一些并非所有动物都有的函数。因此,在Function<Animal, ?>的位置使用Function<Dog, ?>是无效的 - 但反过来是可以的。

英文:

This works:

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

The reason is simple:

To sort a List of Animal using a Comperator, it needs to be a Comperator&lt;Animal&gt;. This means the function you pass into Comperator.comparing needs to
be of a Function&lt;? super Animal,? extends Comperable&gt;. This is not
true for Function&lt;Dog, String&gt;, however it is true for
Function&lt;Animal, String&gt; and Function&lt;Object, String&gt;.

You correctly define your .sort() to take a Function&lt;Animal, String&gt; - but you pass in a member function of Dog - this is essentialla a Function Dog -&gt; String, or Function&lt;Dog,String&gt; in functional interfaces.


In less technical terms: yes, a Dogcan do everything an Animal can. The way around however is not true - a Dog can have a function that not all animals have. Therefore, it's not valid to use a Function&lt;Dog,?&gt; in place of a Function&lt;Animal,?&gt; - but it would be ok the way around.

huangapple
  • 本文由 发表于 2020年5月5日 05:28:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/61601946.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定