为什么我不能将 lambda 分配给未类型化的谓词引用?但是可以为它分配一个初始化的类型谓词引用吗?

Why can't i assign a lambda to an untyped predicate reference? but can assign an initialized typed predicate reference to it?

我在尝试创建基于方法参数类型使用的自定义谓词引用时注意到一些奇怪的事情。

我有一个名为 AffiliateLinkSubset 的对象,它有一个名为 isGeneral 的布尔值 getter。当我尝试执行以下操作时:

Predicate<?> partitionPredicate = AffiliateLinkSubset::isGeneral;

我收到错误 non-static method cannot be referenced from a static context

但是当我将通用类型 AffiliateLinkSubset 分配给它工作的 Predicate 时,这没什么特别的。但是特别的是以下内容也有效:

Predicate<AffiliateLinkSubset> partitionPredicate = affiliateLinkSubset::isGeneral;
Predicate<?> test = partitionPredicate;

IDE没有报错!即使我有效地将相同的 lambda 分配给无类型谓词测试。这怎么可能?谓词会在运行时起作用吗?我假设它会,因为在编译期间所有类型都被擦除并替换为 Object 类型。这就是为什么我不明白为什么我不能为一个无类型的谓词分配一个 lambda。谁能解释一下?

AffiliateLinkSubset实际是class的缩写,这里是:

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;
    }
}
AffiliateLinkSubsetForStatisticsCalculation::isGeneral 

表示

(AffiliateLinkSubsetForStatisticsCalculation i) -> i.isGeneral()

affiliateLinkSubsetForStatisticsCalculationInstance::isGeneral

指的是 (1) AffiliateLinkSubsetForStatisticsCalculation 的实例方法 boolean isGeneral(Object o) 或 (2) Object 的实例方法 boolean isGeneral()

由于这些方法都不存在,您可以编写一个方法参考。但是你可以写一个 lambda:

Predicate<?> p = (Object i) -> affiliateLinkSubsetForStatisticsCalculationInstance.isGeneral();

*AffiliateLinkSubsetForStatisticsCalculation 是 class 名称。
**affiliateLinkSubsetForStatisticsCalculationInstance 是 class.

的实例

首先,Predicate<?> predicate 无法工作,因为未知类型。它们中的任何一个都可以工作:

Predicate<? extends AffiliateLinkSubset> predicate = AffiliateLinkSubset::isGeneral;
Predicate<AffiliateLinkSubset> predicate = AffiliateLinkSubset::isGeneral;

方法引用快捷方式 AffiliateLinkSubset::isGeneral 被理解为 object -> object.isGeneral() 其中 objectAffiliateLinkSubset 的一种类型。这就是第一个谓词无法工作的原因,因为 <?> 没有定义 AffiliateLinkSubset 的类型。 isGeneral() 方法未在 Object 中定义。

让我们继续。如果您键入:

Predicate<?> partitionPredicate = object -> AffiliateLinkSubset.isGeneral();

这不会编译,因为您对待 class 方法 isGeneral() 的方式与静态方法相同。为此,您需要一个可以调用此方法的 class 实例:

AffiliateLinkSubset affiliateLinkSubset = new AffiliateLinkSubset();
Predicate<?> partitionPredicate = object -> affiliateLinkSubset.isGeneral();

现在,objectObject 的一个实例,结果依赖于 lambda 的右侧,它不接触 object 并且与输入无关,因此这也可能有效:

Supplier<Boolean> supplier = () -> affiliateLinkSubset.isGeneral();

这没有多大意义,所以我猜你已经提到了解决方案:

Predicate<? extends AffiliateLinkSubset> predicate = AffiliateLinkSubset::isGeneral;