在尝试创建基于方法参数类型使用的自定义谓词引用时,我注意到了一些奇怪的事情。
我有一个名为AffiliateLinkSubset
的对象,它有一个名为isGeneral的布尔型吸气剂。当我尝试执行以下操作时:
Predicate<?> partitionPredicate = AffiliateLinkSubset::isGeneral;
我收到错误non-static method cannot be referenced from a static context
。
但是当我将通用类型AffiliateLinkSubset
分配给谓词时,这没什么特别的。然而,特别的是,以下内容也起作用:
Predicate<AffiliateLinkSubset> partitionPredicate = affiliateLinkSubset::isGeneral;
Predicate<?> test = partitionPredicate;
IDE对此没有错误!即使我实际上将相同的lambda分配给了无类型谓词测试。这怎么可能?谓词会在运行时起作用吗?我猜想是因为在编译过程中所有类型都被擦除并替换为Object类型。这就是为什么我不明白为什么无法分配无类型谓词lambda的原因。谁能解释?
AffiliateLinkSubset
是实际类的缩写,在这里是:
import POJOs.PojoENUMS.LocalizedStorefront;
import java.util.Map;
import java.util.Set;
public class AffiliateLinkSubsetForStatisticsCalculation {
private Long id;
private String title;
private Double productValue;
private boolean general;
private Set<String> keywords;
private Map<String, Boolean> booleanKeywords;
private LocalizedStorefront localizedStorefront;
public AffiliateLinkSubsetForStatisticsCalculation(Long id, String title, Double productValue, boolean general, Set<String> keywords, Map<String, Boolean> booleanKeywords, LocalizedStorefront localizedStorefront) {
this.id = id;
this.title = title;
this.productValue = productValue;
this.general = general;
this.keywords = keywords;
this.booleanKeywords = booleanKeywords;
this.localizedStorefront = localizedStorefront;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Double getProductValue() {
return productValue;
}
public void setProductValue(Double productValue) {
this.productValue = productValue;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public boolean isGeneral() {
return general;
}
public void setGeneral(boolean general) {
this.general = general;
}
public Set<String> getKeywords() {
return keywords;
}
public void setKeywords(Set<String> keywords) {
this.keywords = keywords;
}
public Map<String, Boolean> getBooleanKeywords() {
return booleanKeywords;
}
public void setBooleanKeywords(Map<String, Boolean> booleanKeywords) {
this.booleanKeywords = booleanKeywords;
}
public LocalizedStorefront getLocalizedStorefront() {
return localizedStorefront;
}
public void setLocalizedStorefront(LocalizedStorefront localizedStorefront) {
this.localizedStorefront = localizedStorefront;
}
}
答案 0 :(得分:4)
首先,由于类型未知,Predicate<?> predicate
无法正常工作。他们中的任何一个都可以工作:
Predicate<? extends AffiliateLinkSubset> predicate = AffiliateLinkSubset::isGeneral;
Predicate<AffiliateLinkSubset> predicate = AffiliateLinkSubset::isGeneral;
方法引用快捷方式AffiliateLinkSubset::isGeneral
被理解为object -> object.isGeneral()
,其中object
是AffiliateLinkSubset
的类型。这就是为什么第一个谓词无法工作的原因,因为<?>
并未定义AffiliateLinkSubset
的类型。 isGeneral()
中未定义Object
方法。
让我们继续。如果您输入:
Predicate<?> partitionPredicate = object -> AffiliateLinkSubset.isGeneral();
由于您将类方法isGeneral()
视为静态方法,因此无法编译。为此,您需要一个可以调用此方法的类的实例:
AffiliateLinkSubset affiliateLinkSubset = new AffiliateLinkSubset();
Predicate<?> partitionPredicate = object -> affiliateLinkSubset.isGeneral();
现在,object
是Object
的实例,结果依赖于lambda的右侧,该lambda不会触及object
且与输入无关,因此这可能也可以:
Supplier<Boolean> supplier = () -> affiliateLinkSubset.isGeneral();
这没有多大意义,所以我想您已经提到过的解决方案:
Predicate<? extends AffiliateLinkSubset> predicate = AffiliateLinkSubset::isGeneral;
答案 1 :(得分:1)
AffiliateLinkSubsetForStatisticsCalculation::isGeneral
表示
(AffiliateLinkSubsetForStatisticsCalculation i) -> i.isGeneral()
同时
affiliateLinkSubsetForStatisticsCalculationInstance::isGeneral
是指(1)boolean isGeneral(Object o)
的实例方法AffiliateLinkSubsetForStatisticsCalculation
或(2)boolean isGeneral()
的实例方法Object
。
由于这些方法都不存在,因此您可以编写方法参考。但是您可以写一个lambda:
Predicate<?> p = (Object i) -> affiliateLinkSubsetForStatisticsCalculationInstance.isGeneral();
* {AffiliateLinkSubsetForStatisticsCalculation
是类名。
** {affiliateLinkSubsetForStatisticsCalculationInstance
是该类的实例。