尝试与消费者一起理解泛型。
msg='This %(key1)s contains custom %(key2)s'
dict={'key1':'string','key2':'placeholders'}
print(msg%dict)
>> This string contains custom placeholders
我收到编译错误:
class Fruit{}
class Apple extends Fruit{}
class Orange extends Fruit{}
class Util{
private Collection<Apple> appleList = new ArrayList<>();
public Util(){
acceptFruit(ap -> appleList.add(ap);
}
public <T extends Fruit> void acceptFruit(Consumer<T> fruitConsumer){
//FruitService.getAllFruits();
//some validations and get fruit object
fruitConsumer.accept(fruit);
}
}
//Some other class calling Util.acceptFruit(orange -> oranges.add(orange);
以及:
acceptFruit(ap -> appleList.add(ap);
add (Apple) in Collection can not be applied to (Fruit)
由于fruit.accept(fruit);
accept (T) in Consumer cannot be applied to (Apple)
正在延长Apple
,我不明白为什么会收到此错误?关于泛型/消费者概念中缺少什么的任何想法?
答案 0 :(得分:3)
Apple
可能是Fruit
,但Collection<Apple>
不 a Collection<Fruit>
。这是由于泛型类型的不变性。
忽略acceptFruit
内部的编译错误(对我来说完全不清楚你开始做什么),最好的方法是确保你的集合包含你要与之交互的超类任何子类。
private Collection<Fruit> fruitList = new ArrayList<>();
这样,您可以在消费者中消费您想要的任何水果。
比这更先进的东西 - 也就是说,消费特定种类的水果 - 比我们这里的基本仿制药更先进,最好留给读者练习。
答案 1 :(得分:0)
Apple
是Fruit
的子类型,但不知道Apple
是T
的子类型,它是未知类型 。 T
可以是Fruit
,Orange
或Banana
,一般来说Apple
不能是所有这些的子类型。
宣布acceptFruit
方法的方式并不真正有意义,因为作为一种通用方法,这意味着无论T
是什么,它都必须正常工作。 acceptFruit
的来电者可以通过T
来调用它,无论来电者想要什么,acceptFruit
必须正常正常工作,而不知道T
是什么。因此acceptFruit
接受一个参数Consumer
,但acceptFruit
在运行时并不知道Consumer
想要什么类型 - 它可能是{{1}一次调用,以及Consumer<Apple>
下一次调用 - 但Consumer<Orange>
无法推断特定调用中需要的类型,因为它没有任何其他参数可以告诉它是什么。为了调用acceptFruit
,它需要传入一个未知类型的实例。因此fruitConsumer
可以安全编写的唯一方法是:1)它根本不会调用acceptFruit
;或者2)它总是将fruitConsumer
传递给null
。
答案 2 :(得分:-1)
您的acceptFruit()
很奇怪,因为它会调用fruit.accept(fruit)
。此代码将消费者自身作为参数调用,这会引起泛型中的所有混乱。你必须将apple的实例传递给消费者,所以这里是你的代码没有错误:
class Util {
private Collection<Apple> appleList = new ArrayList<>();
public Util(){
acceptFruit(ap -> appleList.add(ap), new Apple());
}
public <T extends Fruit> void acceptFruit(Consumer<T> fruitConsumer, T fruit){
//FruitService.getAllFruits();
//some validations and get fruit object
fruitConsumer.accept(fruit);
}
}