Groovy';s@CompileStatic和映射构造函数
我第一次使用Groovy';s@CompileStatic和映射构造函数,groovy,Groovy,我第一次使用@CompileStatic,对Groovy的映射构造函数在这种情况下的工作方式感到困惑 @CompileStatic class SomeClass { Long id String name public static void main(String[] args) { Map map = new HashMap() map.put("id", 123L) map.put("name", "test fi
@CompileStatic
,对Groovy的映射构造函数在这种情况下的工作方式感到困惑
@CompileStatic
class SomeClass {
Long id
String name
public static void main(String[] args) {
Map map = new HashMap()
map.put("id", 123L)
map.put("name", "test file")
SomeClass someClass1 = new SomeClass(map) // Does not work
SomeClass someClass2 = map as SomeClass // Works
}
}
根据上面的代码,我在尝试编译时看到以下错误
Groovyc:尚未设置构造函数调用表达式的目标构造函数
如果删除了@CompileStatic
,则两个构造函数都能正常工作
谁能解释一下为什么newsomeclass(map)
不能用@CompileStatic
编译?还有一个可能的补充,为什么映射为SomeClass
仍然有效?如文档所述:
将实际确保推断为
调用的将在运行时有效调用。此注释将
将Groovy编译器转换为静态编译器,其中所有方法调用都是
在编译时解析,生成的字节码确保
这种情况会发生
因此,在静态编译中搜索带有Map参数的构造函数以“在编译时解析”,但未找到该构造函数,因此存在编译错误:
Target constructor for constructor call expression hasn't been set
添加这样的构造函数可以解决@CompileStatic
注释的问题,因为它是在编译时解决的:
import groovy.transform.CompileStatic
@CompileStatic
class SomeClass {
Long id
String name
SomeClass(Map m) {
id = m.id as Long
name = m.name as String
}
public static void main(String[] args) {
Map map = new HashMap()
map.put("id", 123L)
map.put("name", "test file")
SomeClass someClass1 = new SomeClass(map) // Now it works also
SomeClass someClass2 = map as SomeClass // Works
}
}
如果你想挖得更深,你可以检查一下
关于线路
SomeClass someClass2 = map as SomeClass
您在那里使用的是方法,因此即使在静态编译中,也会在运行时解决:
将此映射强制为给定类型,使用映射的键作为公共
方法名称和值作为实现。通常是值
将是一个行为类似于方法实现的闭包
Groovy实际上没有给你一个“映射构造函数”。建设者 你在课堂上写的是什么。如果没有(如您的情况), 然后是默认的c'tor 但是,如果你使用所谓的map c'tor(或者更确切地说,称之为map c'tor),会发生什么呢 “通过映射构造对象”)?groovy的一般方法如下:
- 使用默认的c'tor创建一个新对象(这就是为什么
根据地图进行施工已不再有效,如果只有。
)SomeClass(长id、字符串名)
- 然后使用传递的映射并将所有值应用于属性
@CompileDynamic
(默认值))禁用代码,您会看到
构造由CallSite.callConstructor(Object,Object)
,,
归结起来就是这个
现在通过地图引入这个构造的版本,这是更熟悉的
对于普通的Groovy开发者:
SomeClass-someClass3=新的SomeClass(id:42L,名称:“道格拉斯”)
对于代码的动态版本,它的反汇编实际上看起来很简单
很喜欢你的地图代码。Groovy从参数和
将其发送到callConstructor
——因此这实际上是相同的代码路径
采取(减去隐式贴图创建)
现在请忽略“cast case”,因为它实际上对于静态和静态都是相同的
动态:它将被发送到ScriptBytecodeAdapter.asType
,基本上
在任何情况下都能为您提供动态行为
现在是@CompileStatic
案例:如您所见,您的呼叫
c'tor的显式映射不再有效。这是因为
首先,从来没有一个明确的“map-c'tor”。全班同学还在上课
只有默认的c'tor和静态编译groovyc
现在才可以
处理存在的事物(如果在本例中没有,则处理不存在的事物)
那新的SomeClass(id:42L,名字:“Douglas”)呢?这仍然有效
使用静态编译!这样做的原因是,groovyc
为你。如您所见,这可以归结为defo=newsomeclass();
o、 setId(42);o、 setName('Douglas')
:
new#2//class SomeClass
重复
调用特殊的#53//方法“”:()V
阿斯托雷2
ldc2_w#54/长42l
dup2
奥斯托雷3
aload_2
lload_3
invokestatic#45//方法java/lang/Long.valueOf:(J)Ljava/lang/Long;
invokevirtual#59//方法setId:(Ljava/lang/Long;)V
空的
流行音乐
pop2
ldc#61//String Douglas
重复
阿斯托尔5号
aload_2
阿洛德5号
invokevirtual#65//方法setName:(Ljava/lang/String;)V
我认为答案比公认的好。谢谢
new #2 // class SomeClass
dup
invokespecial #53 // Method "<init>":()V
astore_2
ldc2_w #54 // long 42l
dup2
lstore_3
aload_2
lload_3
invokestatic #45 // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
invokevirtual #59 // Method setId:(Ljava/lang/Long;)V
aconst_null
pop
pop2
ldc #61 // String Douglas
dup
astore 5
aload_2
aload 5
invokevirtual #65 // Method setName:(Ljava/lang/String;)V