Java 普通实例化和包含方法引用的实例化之间的差异

Java 普通实例化和包含方法引用的实例化之间的差异,java,java-8,java-stream,method-reference,Java,Java 8,Java Stream,Method Reference,为什么在第一种情况下SomeClass只实例化一次,而在第二种情况下实例化n次,其中n是流中的元素数 List<SomeClass> list = stream.map(new SomeClass()::method) .collect(Collectors.toList()); 和SomeClass.java: public class SomeClass { public SomeClass() {

为什么在第一种情况下SomeClass只实例化一次,而在第二种情况下实例化n次,其中n是流中的元素数

List<SomeClass> list = stream.map(new SomeClass()::method)
                            .collect(Collectors.toList());

和SomeClass.java:

public class SomeClass {
    
    public SomeClass() {
        System.out.println(this);
    }
    
    public SomeClass method(Boolean b) {
        return this;
    }
}

因为在第一个代码段中,您只调用了一次
newsomeclass()
,因为:

List<SomeClass> list = stream.map(new SomeClass()::method)
                             .collect(Collectors.toList());
List List=stream.map(新的SomeClass()::方法)
.collect(Collectors.toList());
实际上等于:

SomeClass s = new SomeClass();
List<SomeClass> list = stream.map(a -> s.method(a))
                             .collect(Collectors.toList());
SomeClass s=newsomeclass();
List=stream.map(a->s.method(a))
.collect(Collectors.toList());

在实例
s
上调用方法
method()
,在第一个代码段中,该实例只是没有保存到变量中,而是直接使用方法引用,方法引用只有四种类型(请参见中的“方法引用的类型”):

  • 对静态方法的引用
  • 对特定对象的实例方法的引用
  • 对特定类型的任意对象的实例方法的引用
  • 对构造函数的引用
没有一种方法引用“每次都创建一个新对象”,不管这意味着什么
newsomeclass()::methodName
属于第二类。它指的是一个特定对象的方法
methodName
。该对象是新创建的
SomeClass
对象。调用该方法时,它不会再创建任何
SomeClass
对象,因为它是对新创建的特定
SomeClass
对象的
someMethod
的引用


另一方面,lambda表达式每次被调用时都会创建一个新的
SomeClass
,因为
newsomeclass()
位于
{…}
newsomeclass()
静态部分中,所以不会创建新对象,我想我无法重现这个问题。很明显,您丢失了一些信息。发布一个可验证的例子。我添加了一个复制的例子。这是一个错误的假设。它将被包装在一个方法体中。@ConcurrentBhai我不太明白你的意思。我错在哪里?方法体中包含了什么?“实际上等于这个”是绝对错误的<代码>新建SomeClass()::方法将被包装在方法体中。打开
javap
查看它。@ConcurrentBhai,它们没有相同的密码。在第一种情况下,
SomeClass
在调用lambda时实例化。在第二种情况下,它在创建方法引用之前被实例化。如果要将方法引用转换为lambda,必须首先在局部变量中捕获实例(如Lino的回答),然后将lambda声明为
a->s.method(a)
。在等效代码中再次使用方法引用有点误导,因为这需要转换为等效代码(使用捕获的值)再次执行。最好在第二个代码中使用
a->s.method(a)
。如果表达式不是一个
new
操作,它永远不会
null
,则等效代码类似于
SomeClass s=Objects.requirennoull(表达式);…a->s.method(a)…
。你能告诉我第二类的作用域是什么吗?我的意思是,如果我有另一个具有相同逻辑的类,那么方法引用中的实例只创建了1或2个?@thang这与作用域无关,因为方法引用不是声明。我也不太理解你的第二个问题……你能给我看一些代码吗请说明您的意思?很抱歉,问题不清楚,如果我用相同的代码创建另一个类:
List List=stream.map(new SomeClass()::method).collect(Collectors.toList());
。现在我们有两个类具有相同的方法引用。SomeClass()是否会用新实例创建?@thang是的,因为有两个
new SomeClass()
立即呼叫。
List<SomeClass> list = stream.map(new SomeClass()::method)
                             .collect(Collectors.toList());
SomeClass s = new SomeClass();
List<SomeClass> list = stream.map(a -> s.method(a))
                             .collect(Collectors.toList());