我在阅读泛型时遇到了PECS(制片extends
人和消费者的super
简称).
能否给我一个人解释如何使用佩奇之间解决困惑extends
和super
?
根据我阅读的文献,我们有多汁的实现以下界面:
public interface Juicy<T> {
Juice<T> squeeze();
}
Run Code Online (Sandbox Code Playgroud)
使用有界类型变量,以下方法将获得一堆水果并将它们全部挤压:
<T extends Juicy<T>> List<Juice<T>> squeeze(List<T> fruits);
Run Code Online (Sandbox Code Playgroud)
现在我们还需要更低级的兄弟姐妹来工作:
class Orange extends Fruit implements Juicy<Orange>;
class RedOrange extends Orange;
Run Code Online (Sandbox Code Playgroud)
所以我希望该方法看起来如下:
<T extends Juicy<T>> List<Juice<? super T>> squeeze(List<? extends T> fruits);
Run Code Online (Sandbox Code Playgroud)
相反,我发现方法签名如下:
<**T extends Juicy<? super T>>** List<Juice<? super T>> squeezeSuperExtends(List<? extends T> fruits);
Run Code Online (Sandbox Code Playgroud)
是什么解释了这种差异
给出这段代码片段
//Creates a list of List numbers
List<List<Number>> num = new ArrayList<List<Number>>();
//Creates a list of List doubles
List<List<Double>> doub = new ArrayList<List<Double>>();
//List of doubles
List<Double> d = new ArrayList<Double>();
d.add(2.5);
d.add(2.6);
doub.add(d);
num.add(d);//This code will not compile
Run Code Online (Sandbox Code Playgroud)
为什么不允许num.add(doub)?不是List<List<Number>>
超级型
List<List<Double>>
?
作为这个问题的后续,是否有可能编写一个方法来增加Dog
一个合适的房间?(在这个例子中,它会接受Animal
房间或Dog
房间.)或者我是否被迫写下两种不同的方法如下?(因为类型擦除,我甚至不能依赖重载).
public class Rooms {
interface Animal {}
class Dog implements Animal {}
class Room<T> {
void add(T t) {}
}
void addDogToAnimalRoom(Room<Animal> room) {
room.add(new Dog());
}
void addDogToDogRoom(Room<Dog> room) {
room.add(new Dog());
}
}
Run Code Online (Sandbox Code Playgroud) 我有这个方法来检索作为给定类的实例的对象:
public class UtilitiesClass {
public static final Collection<Animal> get(Collection<Animal> animals, Class<? extends Animal> clazz) {
// returns the Animals which are an instanceof clazz in animals
}
...
}
Run Code Online (Sandbox Code Playgroud)
要调用该方法,我可以这样做:
Collection<Animal> dogs = UtilitiesClass.get(animals, Dog.class);
Run Code Online (Sandbox Code Playgroud)
这很好,但我也希望能够通过以下两种方式调用该方法:
Collection<Animal> dogs = UtilitiesClass.get(animals, Dog.class);
Run Code Online (Sandbox Code Playgroud)
要么
Collection<Dog> dogsTyped = UtilitiesClass.get(animals, Dog.class);
Run Code Online (Sandbox Code Playgroud)
我的意思是我希望能够将方法的结果存储在Dog Collection或Animal one中,因为我需要Dog.class
扩展Animal.class
我在考虑这样的事情:
public static final <T> Collection<T> get(Class<T extends Animal> clazz) {
// returns the Animals which are an instanceof clazz
}
Run Code Online (Sandbox Code Playgroud)
但它不起作用.任何提示?
编辑:最后,使用@Rohit Jain答案,这是调用UtilitiesClass方法时的解决方案:
Collection<? extends …
Run Code Online (Sandbox Code Playgroud) 在Effective Java中,在“使用有界通配符增加API灵活性”一文中,在谈到PECS(producer-extends,consumer-super)的使用时,作者提到:
Comparable 始终是消费者,因此您通常应该使用 Comparable<? super T> 优先于 Comparable。比较器也是如此;因此,您通常应该使用 Comparator<? super T> 优先于比较器。
我不清楚为什么 Comparables 和 Comparator 被认为是消费者。
在讨论 PECS 的主题之一中,什么是 PECS(生产者扩展消费者超级)?,消费者通常将 Collection 称为某个泛型方法的参数。
而这里 Comparable 只是一个接口。
任何人都可以分享一些见解吗?谢谢!
我正在浏览 java 8 中引入的 Predicate 类,它是函数式接口。Predicate 类中有一个方法和方法,用于将多个谓词组合成一个。
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
Run Code Online (Sandbox Code Playgroud)
我已经阅读了 Java 中 PECS 的概念,但仍然无法理解为什么在 Predicate 的情况下我们使用? super T
. Java 程序员如何决定它将成为消费者而不是生产者。
我的意思是为什么不允许出现编译错误的行:
public class PredicateExample {
public static void main(String[] args) {
Predicate<Number> pred = n -> n.intValue() > 2;
Predicate<Integer> predInt = n -> n > 3;
//Compile error
//pred.and(predInt);
Predicate<Object> predObj = o -> Integer.parseInt(o.toString()) > 4;
pred.and(predObj); //Valid statement
Number n = new …
Run Code Online (Sandbox Code Playgroud) 首先,我对这个不太好的标题表示歉意,我是 Java 新手,不知道如何命名它。
我有一个接口类“TestInterface”:
ublic interface TestInterface {
String getForename();
void setForename(String forename);
String getSurname();
void setSurname(String surname);
}
Run Code Online (Sandbox Code Playgroud)
“TestImpl”实现“TestInterface”:
public class TestImpl implements TestInterface{
private String forename;
private String surname;
@Override
public String getForename() {
return forename;
}
public void setForename(String forename) {
this.forename = forename;
}
@Override
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
}
Run Code Online (Sandbox Code Playgroud)
然后我有一个名为“ExtendTest”的调用,它扩展了“TestImpl”:
public class ExtendTest extends TestImpl{
private String firstLineAddress;
public String getFirstLineAddress() {
return …
Run Code Online (Sandbox Code Playgroud)