Java 8方法引用到非静态方法

19

为什么这个不起作用?我得到了编译器错误“无法对非静态方法print进行静态引用...”

public class Chapter3 {
    public void print(String s) {
        System.out.println(s);
    }
    public static void main(String[] args) {
        Arrays.asList("a", "b", "c").forEach(Chapter3::print);
    }
}
6个回答

27

如果您正在尝试从代码运行的同一对象中应用实例方法,那么请注意

Arrays.asList("a", "b", "c").forEach(this::print);

24
无论您使用方法引用、Lambda表达式还是普通的方法调用,实例方法都需要适当的实例进行调用。实例可以由函数调用提供,例如,如果forEach期望一个BiConsumer<Chapter3,String>,则它会工作。但是,由于forEach在您的情况下期望一个Consumer<String>,因此没有Chapter3的实例在范围内。您可以通过将Chapter3.print更改为静态方法或提供实例作为方法调用的目标来轻松解决这个问题:
public class Chapter3 {
    public void print(String s) {
        System.out.println(s);
    }
    public static void main(String[] args) {
        Arrays.asList("a", "b", "c").forEach(new Chapter3()::print);
    }
}

这里,new Chapter3()的结果,即一个新的Chapter3实例,将被捕获用于该方法引用其print方法,然后可以构建一个Consumer<String>调用该实例上的方法。


1
没有Chapter3的实例在范围内......谢谢你解决了我的疑惑。 - Tushar Pandey

10

forEach接受一个Consumer<? super T>(其签名为default void forEach(Consumer<? super T> action)),它是一个具有单个参数的函数式接口,该方法为accept(T t)

当您传递一个带有参数的非静态方法引用时,实际上有两个参数-对Chapter3实例的this引用和String参数。这与forEach期望的不匹配。


6
我想我现在明白了。流中的内容是字符串类型,因此我不能在字符串实例上调用print...
例如,这个可以工作。
public class Chapter3 {
final String value;

public Chapter3(String value) {
    this.value = value;
}

public void print() {
    System.out.println(value);
}

public static void main(String[] args) {
    Arrays.asList(new Chapter3("a"), new Chapter3("b")).forEach(Chapter3::print);
}
}

0
如果您在函数和正在生成该函数的对象之间类型不匹配,您将看到非静态错误。例如,此行代码将无法编译,因为该函数期望 Foo 作为其操作类型,但该函数适用于 Foobar。
Function<Foo, Bar> func = Foobar::getBar;

它不仅仅处理for循环或任何其他参数时的情况,也不必处理“在作用域内”的问题。这是一种类型不匹配错误,当使用新的函数对象时,Java错误地标记了它。与构造其他泛型的情况相比较:

List<Foo> list = new ArrayList<Bar>();

那行代码将无法编译,并提示“不兼容的类型”错误。 更好的是,即使使用几乎相同的方式处理功能对象,这段代码也会出现不兼容类型的错误:
public void test() {
    Function<Foo, Double> test2 = Foo::getDouble;
    //fails with Incompatible types
    test3(test2);
}


public void test3(Function<Foobar, Double> function) {
    //who cares
}

我的最佳建议是,当您开始遇到此错误时,将函数声明拆分到新行中,这样您就可以看到实际问题是什么了。为什么Java选择“非静态方法无法从静态上下文中引用”超出了我的理解。


-1
你可以将你的print函数设置为static,这样就不需要实例来调用它了:
public class Chapter3 {
    public static void print(String s) {
        System.out.println(s);
    }
    public static void main(String[] args) {
        Arrays.asList("a", "b", "c").forEach(Chapter3::print);
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接