在Java中,我们有Class::new构造函数引用的语法.我知道,方法有可调用的引用,但构造函数如何?我的一个典型用例是工厂.
为什么以下第一个示例不起作用?
run(R::new);方法R.run未被调用.run(new R());方法R.run 被调用.这两个例子都是可编译的.
public class ConstructorRefVsNew {
public static void main(String[] args) {
new ConstructorRefVsNew().run(R::new);
System.out.println("-----------------------");
new ConstructorRefVsNew().run(new R());
}
void run(Runnable r) {
r.run();
}
static class R implements Runnable {
R() {
System.out.println("R constructor runs");
}
@Override
public void run() {
System.out.println("R.run runs");
}
}
}
Run Code Online (Sandbox Code Playgroud)
输出是:
R constructor runs
-----------------------
R constructor runs
R.run runs
Run Code Online (Sandbox Code Playgroud)
在第一个示例中,R调用构造函数,它返回lambda(不是对象):
但是,如何成功编译示例怎么可能呢?
给出以下代码:
package com.gmail.oksandum.test;
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(String[] args) {
}
public void foo() {
class LocalFoo {
LocalFoo(String in) {
//Some logic
}
}
List<String> ls = new ArrayList<>();
ls.stream().map(LocalFoo::new); //Line 21
}
}
Run Code Online (Sandbox Code Playgroud)
我的IDE没有给我任何错误.也就是说,直到我尝试构建项目并运行它.当我这样做它给我一个编译器错误,如下所示:
Error:(21, 24) java: incompatible types: cannot infer type-variable(s) R
(argument mismatch; invalid constructor reference
cannot access constructor LocalFoo(java.lang.String)
an enclosing instance of type com.gmail.oksandum.test.Test is not in scope)
Run Code Online (Sandbox Code Playgroud)
现在,我想,给出错误消息,如果foo()是静态的,这不会发生.而且非常正确,只有当foo()是实例方法时才会发生这种情况.只有当LocalFoo是实例方法中的本地类时才会发生,并且只有在使用构造函数引用时才会发生(即从不是常规方法引用).
更重要的是,如果我将第21行改为
ls.stream().map(str -> new LocalFoo(str));
Run Code Online (Sandbox Code Playgroud)
编译器突然没有错误.
所以回顾一下.如果我尝试在实例方法中声明的本地类上使用构造函数引用,编译器会抱怨无法访问构造函数,我很困惑.
如果有人能够阐明为什么会发生这种情况,我们将不胜感激.谢谢.
我学习了Java 8的新功能.
我正在玩不同的例子,我发现了一个奇怪的行为:
public static void main(String[] args) {
method(Test::new);
}
static class Test{
}
private static void method(Supplier<Test> testSupplier){
Test test = testSupplier.get();
}
Run Code Online (Sandbox Code Playgroud)
这段代码编译成功,但我不知道它是如何工作的.
为什么可以Test::new接受供应商?
供应商界面看起来很简单:
@FunctionalInterface
public interface Supplier<T> {
T get();
}
Run Code Online (Sandbox Code Playgroud) 我正在使用lambda为内部类构造函数创建供应商ctx -> new SpectatorSwitcher(ctx).IntelliJ建议我将其SpectatorSwitcher::new改为.SpectatorSwitcher是我正在使用的类的非静态内部类.建议的代码编译得很好(使用maven)但我在执行时得到以下VerifyError:
Exception in thread "main" java.lang.VerifyError: Bad type on operand stack
Exception Details:
Location:
Test.lambda$runTest$8(LTest$Worker;)V @2: invokedynamic
Reason:
Type 'Test$Worker' (current frame, stack[1]) is not assignable to 'Test'
Current Frame:
bci: @2
flags: { }
locals: { 'Test$Worker' }
stack: { 'Test$Worker', 'Test$Worker' }
Bytecode:
0000000: 2a2a ba00 0b00 00b6 000c b1
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2688)
at java.lang.Class.getMethod0(Class.java:2937)
at java.lang.Class.getMethod(Class.java:1771)
at sun.launcher.LauncherHelper.validateMainClass(LauncherHelper.java:544)
at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:526)
Run Code Online (Sandbox Code Playgroud)
为什么javac/maven在编译时没有失败但仍然产生无效的字节代码?
编辑:问题似乎比简单调用复杂得多,这是重现它所需的代码:
import java.util.function.Function;
/**
* @author …Run Code Online (Sandbox Code Playgroud) 我正在阅读perform message它附带的样本我重现..
@FunctionalInterface
public interface Action {
public void perform();
}
Run Code Online (Sandbox Code Playgroud)
实施者
public final class ActionImpl implements Action {
public ActionImpl() {
System.out.println("constructor[ActionIMPL]");
}
@Override
public void perform() {
System.out.println("perform method is called..");
}
}
Run Code Online (Sandbox Code Playgroud)
来电者.
public final class MethodReferences {
private final Action action;
public MethodReferences(Action action) {
this.action = action;
}
public void execute() {
System.out.println("execute->called");
action.perform();
System.out.println("execute->exist");
}
public static void main(String[] args) {
MethodReferences clazz = new MethodReferences(new ActionImpl());
clazz.execute();
}
}
Run Code Online (Sandbox Code Playgroud)
如果调用此方法则将以下内容打印到输出中
constructor[ActionIMPL] …Run Code Online (Sandbox Code Playgroud) 我有一个PersonFactory如下界面:
@FunctionalInterface
public interface PersonFactory<P extends Person> {
P create(String firstname, String lastname);
// Return a person with no args
default P create() {
// Is there a way I could make this work?
}
}
Run Code Online (Sandbox Code Playgroud)
本Person类:
public class Person {
public String firstname;
public String lastname;
public Person() {}
public Person(String firstname, String lastname) {
this.firstname = firstname;
this.lastname = lastname;
}
}
Run Code Online (Sandbox Code Playgroud)
我希望能够Person像这样实例化我的:
PersonFactory<Person> personFactory = Person::new;
Person p = personFactory.create(); // …Run Code Online (Sandbox Code Playgroud) java java-8 functional-interface method-reference constructor-reference
假设以下代码:
class ConstructMe<T> {}
data class Test<T> constructor(var supplier: () -> ConstructMe<T>) {}
fun main(args: Array<String>) {
works<Int>()
breaks<Int>()
}
fun <T> works() {
Test<T>({ ConstructMe<T>() }) // (1) any one class type parameter can be removed like:
Test({ ConstructMe<T>() }) // (2) still works (class type inferred by argument type)
Test<T>({ ConstructMe() }) // (3) still works (argument type inferred by class type)
}
fun <T> breaks() {
Test<T>(::ConstructMe) // type interference failed (should probably work like (3); compiler …Run Code Online (Sandbox Code Playgroud) generics reflection type-parameter kotlin constructor-reference
像这样的代码
public class LambdaTest {
public static void main(String[] args) {
final Animal animal = Dog::new;
animal.eat();
}
}
@FunctionalInterface
interface Animal {
void eat();
}
class Dog implements Animal {
public Dog() {
System.out.println("dog init.");
}
@Override
public void eat() {
System.out.println("dog eat");
}
Run Code Online (Sandbox Code Playgroud)
当我运行这段代码时,“dog init”。被打印到控制台,但“dog eat”却没有。这是为什么?有人能告诉我原因吗?
我预计会打印“dog init”和“dog eat”,但只打印了“dog init”。另外,我很困惑为什么在Animal animal = Dog::new;.
Java语言规范Java 8的第15.13节描述了这种形式的方法参考语法,用于创建构造函数引用:
ClassType :: [TypeArguments] new
Run Code Online (Sandbox Code Playgroud)
例如:
String s = "abc";
UnaryOperator<String> test0 = String::new; // String(String) constructor.
String s0 = test0.apply(s);
System.out.println("s0 = " + s0); // Prints "abc".
char[] chars = {'x','y','z'};
Function<char[], String> test1 = String::new; // String(char[]) constructor.
String s1 = test1.apply(chars);
System.out.println("s1 = " + s1); // Prints "xyz"
Run Code Online (Sandbox Code Playgroud)
一切正常,但似乎绝对任何东西(不包括原语)也可以为[TypeArguments]提供,一切仍然有效:
这是一个愚蠢的例子来证明这一点:
Function<String, String> test2 = String::<LocalDateTime, Thread[]>new; // Compiles !!!???
String s2 = test2.apply("123");
System.out.println("s2 = " + s2); // Prints "123"
Run Code Online (Sandbox Code Playgroud)
提出几个问题: …