令我惊讶的是,我今天了解到以下内容在Groovy中可以正常工作:
import java.util.concurrent.*
def atomicBool = new atomic.AtomicBoolean(true)
即导入星号后,我可以使用“部分”包来引用java.util.concurrent.atomic.AtomicBoolean
。
很明显,这在Java中无效:
import java.util.concurrent.*;
public class Sample {
public static void main(String[] args) {
// compiler error: 'atomic' cannot be resolved to a type
new atomic.AtomicBoolean(true);
}
}
因此,在这方面,Groovy的软件包概念似乎类似于C ++(或C#)命名空间。
对Groovy专家的疑问:
答案 0 :(得分:3)
基于Groovy源代码,这种行为似乎是有意的。在深入探究Groovy内部之前,您必须了解一件事-Groovy编译为可以由有效Java代码表示的字节码。这意味着Groovy代码(例如您的示例形式)实际上可以编译为以下内容(无需编译静态和类型检查的转换):
import groovy.lang.Binding;
import groovy.lang.Script;
import java.util.concurrent.atomic.AtomicBoolean;
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();
}
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();
AtomicBoolean atomicBool = (AtomicBoolean)ScriptBytecodeAdapter.castToType(var1[1].callConstructor(AtomicBoolean.class, true), AtomicBoolean.class);
return var1[2].callCurrent(this, atomicBool);
}
}
如您所见,该Java类使用完整的java.util.concurrent.atomic.AtomicBoolean
导入,这实际上是Groovy将您的输入源代码转换为的内容。
您可能已经知道Groovy从输入源文件构建了抽象语法树(AST),并在所有节点上进行迭代(如表达式,变量定义,方法调用等)并应用转换。 Groovy使用名为ResolverVisitor
的类来解析类型。当Groovy编译您的代码时,它会发现ConstructorCallExpression
:
new atomic.AtomicBoolean(true)
它看到您要创建的对象的预期类型为atomic.AtomicBoolean
,因此ResolverVisitor
通过调用resolveOrFail(type, cce);
at line 1131开始解析类型。
它将尝试几种失败的until it reaches method resolveFromModule
at line 695解决策略。此处发生的事情是遍历所有星号导入(在您的情况下为单个java.util.concurrent.*
),然后将星型导入与类型名称连接起来,并检查从此串联创建的合格名称是否为有效的类型类。幸运的是,您的情况是这样:
当类型被解析时,Groovy在抽象语法树中将初始类型替换为此解析的有效类型名称。完成此操作后,您的输入代码将更像这样:
import java.util.concurrent.*
java.util.concurrent.atomic.AtomicBoolean atomicBool = new java.util.concurrent.atomic.AtomicBoolean(true)
这是编译器最终得到的。当然,完全限定的名称会被导入替换(这是Java编译器对限定名称的处理)。
我不能告诉你。但是我们可以从源代码中读取到,这是有意发生的,而类型解析是有意实现的。
我猜没有人真正建议以这种方式使用导入。 Groovy非常强大,您可以通过许多不同的方式来做很多事情,但这并不意味着您应该这样做。星号导入很有争议,因为在可能的类导入冲突中,使用星号导入而不是显式导入会使您的代码更容易出错。但是,如果您想知道此类问题的确切答案,则必须询问Groovy语言设计师和核心开发人员-他们可能会为您提供毫无疑问的直接答案。