对本地 class 构造函数的方法引用
Method reference to local class constructor
关于对本地 class 构造函数的方法引用,SO 上有几个类似的问题,但我想稍微澄清一下其他事情。考虑以下代码:
static Callable gen(int i) {
class X {
int x = i;
public String toString() { return "" + x; }
}
return X::new;
}
...
System.out.println(gen(0).call());
System.out.println(gen(1).call());
显然这将打印输出
0
1
事实证明,X
class 具有 ...$X(int)
形式的构造函数(您可以通过 X.class.getDeclaredConstructors()
找到它)。
但这里有趣的是,返回的 lambda(或方法引用)并不是对构造函数 ...$X(int)
的简单引用,例如 Integer::new
。他们使用预定义参数(0
或 1
)在内部调用此构造函数 ...$X(int)
。
所以,我不确定,但看起来 JLS 中没有准确描述这种方法参考。除了本地 classes 的这种情况之外,没有其他方法可以生成这种 lambdas(具有预定义的构造函数参数)。谁能帮忙解释一下?
准确地说:
JLS中哪里有这样的方法参考描述?
是否有任何其他方法可以创建对具有预定义参数的任意 class 构造函数的此类方法引用?
此行为在 JLS 部分中定义 §15.13.3:
If the form is ClassType :: [TypeArguments] new, the body of the invocation method has the effect of a class instance creation expression of the form new [TypeArguments] ClassType(A1, ..., An), where the arguments A1, ..., An are the formal parameters of the invocation method, and where:
The enclosing instance for the new object, if any, is derived from the site of the method reference expression, as specified in §15.9.2.
The constructor to invoke is the constructor that corresponds to the compile-time declaration of the method reference (§15.13.1).
虽然这里讨论了封闭 实例 ,但在 §15.13.3.
中没有提到捕获的变量和参数
关于你的第二个问题,你需要手动抓取修改参数:
static Callable gen(int i) {
final int i1 = someCondition() ? i : 42;
class X {
int x = i1; // <-
public String toString() { return "" + x; }
}
return X::new;
}
您过于关注不相关的底层细节。在字节码级别,可能有一个构造函数接受 int
参数,但在语言级别,您没有指定显式构造函数,因此,将有一个不带任何参数的默认构造函数,与任何其他 class.
当您编写 pre-Java 8 代码时,这应该会变得清楚:
static Callable<Object> gen(int i) {
class X {
int x = i;
public String toString() { return "" + x; }
}
X x=new X();
…
您通过其默认构造函数实例化 X
,不接受任何参数。您的本地 class 捕获 i
的值,但它是如何在低级别上实现的,即 X
' 构造函数具有合成 int
参数和 new
表达式会将 i
的值传递给它,是一个实现细节。
您甚至可以添加一个显式构造函数作为
X() {}
没有任何改变。
显然,您也可以在此处将表达式 new X()
写在 lambda 表达式中,因为将表达式放在 lambda 表达式中时不会改变其语义:
return () -> new X();
或者用short-hand的形式,方法参考
return X::new;
它没有什么特别之处,如果您忘记了令人分心的底层细节,即使不参考规范,这种行为也是可以理解的。 X
可以捕获任意多的局部变量,构造函数的参数数量不变(在语言级别)。
关于对本地 class 构造函数的方法引用,SO 上有几个类似的问题,但我想稍微澄清一下其他事情。考虑以下代码:
static Callable gen(int i) {
class X {
int x = i;
public String toString() { return "" + x; }
}
return X::new;
}
...
System.out.println(gen(0).call());
System.out.println(gen(1).call());
显然这将打印输出
0
1
事实证明,X
class 具有 ...$X(int)
形式的构造函数(您可以通过 X.class.getDeclaredConstructors()
找到它)。
但这里有趣的是,返回的 lambda(或方法引用)并不是对构造函数 ...$X(int)
的简单引用,例如 Integer::new
。他们使用预定义参数(0
或 1
)在内部调用此构造函数 ...$X(int)
。
所以,我不确定,但看起来 JLS 中没有准确描述这种方法参考。除了本地 classes 的这种情况之外,没有其他方法可以生成这种 lambdas(具有预定义的构造函数参数)。谁能帮忙解释一下?
准确地说:
JLS中哪里有这样的方法参考描述?
是否有任何其他方法可以创建对具有预定义参数的任意 class 构造函数的此类方法引用?
此行为在 JLS 部分中定义 §15.13.3:
If the form is ClassType :: [TypeArguments] new, the body of the invocation method has the effect of a class instance creation expression of the form new [TypeArguments] ClassType(A1, ..., An), where the arguments A1, ..., An are the formal parameters of the invocation method, and where:
The enclosing instance for the new object, if any, is derived from the site of the method reference expression, as specified in §15.9.2.
The constructor to invoke is the constructor that corresponds to the compile-time declaration of the method reference (§15.13.1).
虽然这里讨论了封闭 实例 ,但在 §15.13.3.
中没有提到捕获的变量和参数关于你的第二个问题,你需要手动抓取修改参数:
static Callable gen(int i) {
final int i1 = someCondition() ? i : 42;
class X {
int x = i1; // <-
public String toString() { return "" + x; }
}
return X::new;
}
您过于关注不相关的底层细节。在字节码级别,可能有一个构造函数接受 int
参数,但在语言级别,您没有指定显式构造函数,因此,将有一个不带任何参数的默认构造函数,与任何其他 class.
当您编写 pre-Java 8 代码时,这应该会变得清楚:
static Callable<Object> gen(int i) {
class X {
int x = i;
public String toString() { return "" + x; }
}
X x=new X();
…
您通过其默认构造函数实例化 X
,不接受任何参数。您的本地 class 捕获 i
的值,但它是如何在低级别上实现的,即 X
' 构造函数具有合成 int
参数和 new
表达式会将 i
的值传递给它,是一个实现细节。
您甚至可以添加一个显式构造函数作为
X() {}
没有任何改变。
显然,您也可以在此处将表达式 new X()
写在 lambda 表达式中,因为将表达式放在 lambda 表达式中时不会改变其语义:
return () -> new X();
或者用short-hand的形式,方法参考
return X::new;
它没有什么特别之处,如果您忘记了令人分心的底层细节,即使不参考规范,这种行为也是可以理解的。 X
可以捕获任意多的局部变量,构造函数的参数数量不变(在语言级别)。