Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/jenkins/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 将非final对象传递给方法引用_Java_Lambda_Java 8_Method Reference_Expression Evaluation - Fatal编程技术网

Java 将非final对象传递给方法引用

Java 将非final对象传递给方法引用,java,lambda,java-8,method-reference,expression-evaluation,Java,Lambda,Java 8,Method Reference,Expression Evaluation,s.get()第二次返回“ONE”的原因是什么 String x = "one"; Supplier<String> s = x::toUpperCase; System.out.println("s.get() = " + s.get()); x = "two"; System.out.println("s.get() = " + s.get()); String x=“一”; 供应商s=x::toUpperCase; System.out.println(“s.get()=”+

s.get()
第二次返回“ONE”的原因是什么

String x = "one";
Supplier<String> s = x::toUpperCase;
System.out.println("s.get() = " + s.get());
x = "two";
System.out.println("s.get() = " + s.get());
String x=“一”;
供应商s=x::toUpperCase;
System.out.println(“s.get()=”+s.get());
x=“两个”;
System.out.println(“s.get()=”+s.get());
更新:

将其与:

String x = "one";
Supplier<String> s = () -> x.toUpperCase();
System.out.println("s.get() = " + s.get());
x = "two";
System.out.println("s.get() = " + s.get());
String x=“一”;
供应商s=()->x.toUpperCase();
System.out.println(“s.get()=”+s.get());
x=“两个”;
System.out.println(“s.get()=”+s.get());

它将引发编译错误。

字符串是一个不可变类,您正在执行

x = "two"; 

保持对象s与之前的值“ONE”保持“完整”

您创建了一个
供应商,它只提供值,在这种情况下,每次都提供相同的值,因为创建lambda时,
x
的值仅转换一次

您需要的是一个
函数
,它接受一个参数并返回一个结果

试试这个:

String x = "one";
Function<String, String> s = String::toUpperCase;
System.out.println("s.apply(x) = " + s.apply(x));
x = "two";
System.out.println("s.apply(x) = " + s.apply(x));
String x=“一”;
函数s=String::toUpperCase;
System.out.println(“s.apply(x)=”+s.apply(x));
x=“两个”;
System.out.println(“s.apply(x)=”+s.apply(x));

在java中,引用对象的变量通常称为
引用
。在上面的代码中有两个引用,
x
s

字符串是不可变的,任何更改都表示另一个对象。一旦创建,就不能修改字符串对象的任何状态

在代码中,
x
s
都被初始化为引用2个对象,然后
x
被设置为引用另一个对象,但是
s
仍然引用同一个对象。请注意,
将立即求值,并对结果对象进行分类
x
可以独立于
y


使用
x=“two”
只能使
x
引用不同的对象

只有lambda表达式()需要传递final或有效final变量。方法引用的评估方式不同

当方法引用表达式在分隔符前面有表达式(而不是类型)时,将立即计算该子表达式。存储评估结果,直到调用相应功能接口类型的方法;此时,结果将用作调用的目标引用。这意味着只有当程序遇到方法引用表达式时,才会对
::
分隔符前面的表达式求值,并且不会在函数接口类型的后续调用中重新求值

因此,变量不必是
final

实际上,它与类是否不可变无关。相反,方法引用的左侧部分是否为表达式很重要

我想举一个简短的例子让大家理解:

class A {
    public static void main(String[] args) {

        Supplier<A> supplier1 = A::new; // (1)
        Supplier<A> supplier2 = new A()::self; // (2) 

        A r1 = supplier1.get(); // (3)
        A r2 = supplier2.get(); // (4)
    }

    private A self() { return this; }

}
A类{
公共静态void main(字符串[]args){
供应商1=A::新;//(1)
供应商2=新A()::self;//(2)
r1=supplier1.get();/(3)
r2=supplier2.get();/(4)
}
private A self(){返回此;}
}
  • 已创建供应商实例,尚未评估结果(类型为的方法引用)
  • 已计算供应商及其结果(使用
    newa()
    表达式的方法引用)
  • 对于每个
    supplier1.get()
    调用,都将对其进行重新评估
  • 将返回步骤2的结果
  • 字符串是不可变的:

    String x = "one";
    Supplier<String> s = x::toUpperCase;
    
    String x=“一”;
    供应商s=x::toUpperCase;
    
    相当于:

    String x = "one";
    Supplier<String> s = "one"::toUpperCase;
    
    String x=“一”;
    供应商s=“一”::toUpperCase;
    
    这个问题很有趣,所以我通过反编译器运行了它-但答案支持Andrew Tobilko的答案

    java -jar cfr_0_119.jar LambdaTest --decodelambdas false
    
    /*
     * Decompiled with CFR 0_119.
     */
    import java.io.PrintStream;
    import java.lang.invoke.LambdaMetafactory;
    import java.util.function.Supplier;
    
    public class LambdaTest {
        public static void main(String[] args) {
            String x = "one";
            Supplier<String> s = (Supplier<String>)LambdaMetafactory.metafactory(null, null, null, ()Ljava/lang/Object;, toUpperCase(), ()Ljava/lang/String;)((String)x);
            System.out.println("s.get() = " + s.get());
            x = "two";
            System.out.println("s.get() = " + s.get());
        }
    }
    
    java-jar cfr_0_119.jar LambdaTest——decodelambdas false
    /*
    *使用CFR 0_119反编译。
    */
    导入java.io.PrintStream;
    导入java.lang.invoke.LambdaMetafactory;
    导入java.util.function.Supplier;
    公共类LambdaTest{
    公共静态void main(字符串[]args){
    字符串x=“一”;
    suppliers=(Supplier)LambdaMetafactory.metafactory(null,null,null,()Ljava/lang/Object;,toUpperCase(),()Ljava/lang/String;)((String)x);
    System.out.println(“s.get()=”+s.get());
    x=“两个”;
    System.out.println(“s.get()=”+s.get());
    }
    }
    
    因此,方法引用获得了x的第一个实例的副本,这就是为什么它两次输出“1”,并且没有创建静态lambda,只调用toUpper

    我还运行了创建lambda的第二个示例(我遗漏了不编译的部分-

    java -jar cfr_0_119.jar LambdaTest --decodelambdas false
    /*
     * Decompiled with CFR 0_119.
     */
    import java.io.PrintStream;
    import java.lang.invoke.LambdaMetafactory;
    import java.util.function.Supplier;
    
    public class LambdaTest {
        public static void main(String[] args) {
            String y = "one";
            Supplier<String> sy = (Supplier<String>)LambdaMetafactory.metafactory(null, null, null, ()Ljava/lang/Object;, lambda$0(java.lang.String ), ()Ljava/lang/String;)((String)y);
            System.out.println("sy.get() = " + sy.get());
        }
    
        private static /* synthetic */ String lambda$0(String string) {
            return string.toUpperCase();
        }
    }
    
    java-jar cfr_0_119.jar LambdaTest——decodelambdas false
    /*
    *使用CFR 0_119反编译。
    */
    导入java.io.PrintStream;
    导入java.lang.invoke.LambdaMetafactory;
    导入java.util.function.Supplier;
    公共类LambdaTest{
    公共静态void main(字符串[]args){
    字符串y=“一”;
    Supplier sy=(Supplier)LambdaMetafactory.metafactory(null,null,null,()Ljava/lang/Object;,lambda$0(java.lang.String),()Ljava/lang/String;)((String)y);
    System.out.println(“sy.get()=”+sy.get());
    }
    私有静态/*合成*/String lambda$0(字符串){
    返回字符串.toUpperCase();
    }
    }
    
    这比“简单的例子”更有趣,因为“引用是指引用,是一个合适的答案”。KelWoo:类似的,我可以说,你可以在C++中写类似于代码>供应商< /COD>的东西,输出“两个”。。第二个示例不应该因为有对实例的方法引用的原因而编译。好吧,该实例是一个文本为“one”的字符串。因此它永远不会更改,因为字符串是不可变的。您最好编写