找不到匿名的匹配构造函数 class
Could not find matching constructor for anonymous class
考虑以下代码示例
class A {
int data
}
class B extends A {}
def o1 = new B(data: 1)
// This works correctly.
def o2 = new A(data:1) {}
// This will throw the following error
// Exception thrown
//
// groovy.lang.GroovyRuntimeException: Could not find matching constructor for: A(LinkedHashMap)
// at ConsoleScript2.<init>(ConsoleScript2)
// at ConsoleScript2.run(ConsoleScript2:11)
// at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
// at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64)
// at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
对我来说,匿名者应该与命名者相同class。但事实证明 Groovy 对他们的态度不同。我想知道如何解决它。谢谢。
您看到此错误是因为动态映射构造函数的性质 - 它不会显式添加到生成的 classes 中,而是通过 CallSite.callConstructor(obj,map)
方法调用。但是,这个问题是有解决办法的。
考虑以下示例性 test.groovy
脚本:
class A {
int data
}
class B extends A {}
def a1 = new B(data: 1)
def a2 = new A(data: 2) {}
println a1
println a2
当你反编译生成的A.class
文件时,你会得到这样的结果:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
import groovy.lang.GroovyObject;
import groovy.lang.MetaClass;
import groovy.transform.Generated;
import groovy.transform.Internal;
import java.beans.Transient;
import org.codehaus.groovy.runtime.callsite.CallSite;
public class A implements GroovyObject {
private int data;
@Generated
public A() {
CallSite[] var1 = $getCallSiteArray();
super();
MetaClass var2 = this.$getStaticMetaClass();
this.metaClass = var2;
}
@Generated
@Internal
@Transient
public MetaClass getMetaClass() {
MetaClass var10000 = this.metaClass;
if (var10000 != null) {
return var10000;
} else {
this.metaClass = this.$getStaticMetaClass();
return this.metaClass;
}
}
@Generated
@Internal
public void setMetaClass(MetaClass var1) {
this.metaClass = var1;
}
@Generated
public int getData() {
return this.data;
}
@Generated
public void setData(int var1) {
this.data = var1;
}
}
这个class只有一个无参构造函数。当你反编译test.class
文件(编译Groovy脚本文件)时,你会看到这样的东西:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
import groovy.lang.Binding;
import groovy.lang.Script;
import org.codehaus.groovy.runtime.InvokerHelper;
import org.codehaus.groovy.runtime.ScriptBytecodeAdapter;
import org.codehaus.groovy.runtime.callsite.CallSite;
public class test extends Script {
public test() {
CallSite[] var1 = $getCallSiteArray();
super();
}
public test(Binding context) {
CallSite[] var2 = $getCallSiteArray();
super(context);
}
public static void main(String... args) {
CallSite[] var1 = $getCallSiteArray();
var1[0].call(InvokerHelper.class, test.class, args);
}
public Object run() {
CallSite[] var1 = $getCallSiteArray();
Object a1 = var1[1].callConstructor(B.class, ScriptBytecodeAdapter.createMap(new Object[]{"data", 1}));
Object a2 = new test.1(ScriptBytecodeAdapter.createMap(new Object[]{"data", 2}));
var1[2].callCurrent(this, a1);
return var1[3].callCurrent(this, a2);
}
public class 1 extends A {
}
}
看看对象 a1
和 a2
是如何初始化的。 a1
对象按以下方式初始化:
Object a1 = var1[1].callConstructor(B.class, ScriptBytecodeAdapter.createMap(new Object[]{"data", 1}));
它使用CallSite.callConstructor()
方法模仿A
class中不存在的地图构造函数。如果我们查看对象 a2
的初始化方式,我们会发现:
Object a2 = new test.1(ScriptBytecodeAdapter.createMap(new Object[]{"data", 2}));
我们可以看到 Groovy 在匿名 class 的情况下(这根本不是匿名的 - Groovy 无论如何都会生成一个 class),Groovy 使用直接构造函数调用。它失败了,因为父 class.
中没有 A(LinkedHashMap)
构造函数
解决方案
幸运的是,这个问题有一个解决方案 - 您可以使用 @MapConstructor
和 @InheritConstructors
注释强制在 A
class 中创建地图构造函数,并在B
class继承这个构造函数。看看这个工作示例:
import groovy.transform.InheritConstructors
import groovy.transform.MapConstructor
@MapConstructor
class A {
int data
}
@InheritConstructors
class B extends A {}
def a1 = new B(data: 1)
def a2 = new A(data: 2) {}
println a1
println a2
唯一的要求是至少使用引入了 @MapConstructor
注释的 Groovy 2.5 版本。
考虑以下代码示例
class A {
int data
}
class B extends A {}
def o1 = new B(data: 1)
// This works correctly.
def o2 = new A(data:1) {}
// This will throw the following error
// Exception thrown
//
// groovy.lang.GroovyRuntimeException: Could not find matching constructor for: A(LinkedHashMap)
// at ConsoleScript2.<init>(ConsoleScript2)
// at ConsoleScript2.run(ConsoleScript2:11)
// at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
// at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64)
// at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
对我来说,匿名者应该与命名者相同class。但事实证明 Groovy 对他们的态度不同。我想知道如何解决它。谢谢。
您看到此错误是因为动态映射构造函数的性质 - 它不会显式添加到生成的 classes 中,而是通过 CallSite.callConstructor(obj,map)
方法调用。但是,这个问题是有解决办法的。
考虑以下示例性 test.groovy
脚本:
class A {
int data
}
class B extends A {}
def a1 = new B(data: 1)
def a2 = new A(data: 2) {}
println a1
println a2
当你反编译生成的A.class
文件时,你会得到这样的结果:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
import groovy.lang.GroovyObject;
import groovy.lang.MetaClass;
import groovy.transform.Generated;
import groovy.transform.Internal;
import java.beans.Transient;
import org.codehaus.groovy.runtime.callsite.CallSite;
public class A implements GroovyObject {
private int data;
@Generated
public A() {
CallSite[] var1 = $getCallSiteArray();
super();
MetaClass var2 = this.$getStaticMetaClass();
this.metaClass = var2;
}
@Generated
@Internal
@Transient
public MetaClass getMetaClass() {
MetaClass var10000 = this.metaClass;
if (var10000 != null) {
return var10000;
} else {
this.metaClass = this.$getStaticMetaClass();
return this.metaClass;
}
}
@Generated
@Internal
public void setMetaClass(MetaClass var1) {
this.metaClass = var1;
}
@Generated
public int getData() {
return this.data;
}
@Generated
public void setData(int var1) {
this.data = var1;
}
}
这个class只有一个无参构造函数。当你反编译test.class
文件(编译Groovy脚本文件)时,你会看到这样的东西:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
import groovy.lang.Binding;
import groovy.lang.Script;
import org.codehaus.groovy.runtime.InvokerHelper;
import org.codehaus.groovy.runtime.ScriptBytecodeAdapter;
import org.codehaus.groovy.runtime.callsite.CallSite;
public class test extends Script {
public test() {
CallSite[] var1 = $getCallSiteArray();
super();
}
public test(Binding context) {
CallSite[] var2 = $getCallSiteArray();
super(context);
}
public static void main(String... args) {
CallSite[] var1 = $getCallSiteArray();
var1[0].call(InvokerHelper.class, test.class, args);
}
public Object run() {
CallSite[] var1 = $getCallSiteArray();
Object a1 = var1[1].callConstructor(B.class, ScriptBytecodeAdapter.createMap(new Object[]{"data", 1}));
Object a2 = new test.1(ScriptBytecodeAdapter.createMap(new Object[]{"data", 2}));
var1[2].callCurrent(this, a1);
return var1[3].callCurrent(this, a2);
}
public class 1 extends A {
}
}
看看对象 a1
和 a2
是如何初始化的。 a1
对象按以下方式初始化:
Object a1 = var1[1].callConstructor(B.class, ScriptBytecodeAdapter.createMap(new Object[]{"data", 1}));
它使用CallSite.callConstructor()
方法模仿A
class中不存在的地图构造函数。如果我们查看对象 a2
的初始化方式,我们会发现:
Object a2 = new test.1(ScriptBytecodeAdapter.createMap(new Object[]{"data", 2}));
我们可以看到 Groovy 在匿名 class 的情况下(这根本不是匿名的 - Groovy 无论如何都会生成一个 class),Groovy 使用直接构造函数调用。它失败了,因为父 class.
中没有A(LinkedHashMap)
构造函数
解决方案
幸运的是,这个问题有一个解决方案 - 您可以使用 @MapConstructor
和 @InheritConstructors
注释强制在 A
class 中创建地图构造函数,并在B
class继承这个构造函数。看看这个工作示例:
import groovy.transform.InheritConstructors
import groovy.transform.MapConstructor
@MapConstructor
class A {
int data
}
@InheritConstructors
class B extends A {}
def a1 = new B(data: 1)
def a2 = new A(data: 2) {}
println a1
println a2
唯一的要求是至少使用引入了 @MapConstructor
注释的 Groovy 2.5 版本。