[英]Groovy star import and usage of “partial” packages
令我驚訝的是,我今天已經了解到以下在Groovy中運行得很好:
import java.util.concurrent.*
def atomicBool = new atomic.AtomicBoolean(true)
即在星型導入之后,我可以使用'partial'包來引用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專家提問:
基於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
import,這實際上是Groovy將您的輸入源代碼轉換為的內容。
您可能知道Groovy從輸入源文件構建抽象語法樹(AST),它迭代所有節點(如表達式,變量定義,方法調用等)並應用轉換。 Groovy使用名為ResolverVisitor
類來解析類型。 當Groovy編譯代碼時,它會找到ConstructorCallExpression
:
new atomic.AtomicBoolean(true)
它看到您嘗試創建的對象的預期類型是atomic.AtomicBoolean
,因此ResolverVisitor
通過調用resolveOrFail(type, cce);
開始解析該類型resolveOrFail(type, cce);
在1131線 。
它嘗試了幾種失敗的解決策略, 直到它到達第695行的方法resolveFromModule
。 這里發生的是迭代所有星型導入(在您的情況下單個java.util.concurrent.*
),然后它將星型導入與類型名稱連接,並檢查從此串聯創建的限定名稱是否是有效的類型類。 幸運的是,在你的情況下:
當類型得到解析時,Groovy會在抽象語法樹中使用此已解析的有效類型名稱替換初始類型。 在此操作之后,您的輸入代碼看起來更像是:
import java.util.concurrent.*
java.util.concurrent.atomic.AtomicBoolean atomicBool = new java.util.concurrent.atomic.AtomicBoolean(true)
這是編譯器最終得到的。 當然,完全限定名稱會被導入替換(這是Java編譯器使用限定名稱執行的操作)。
我不能告訴你。 但是我們可以從源代碼中讀取,這是故意發生的,類型解析就像這樣實現。
我想沒有人真的建議那樣使用進口。 Groovy非常強大,你可以用很多不同的方式做很多事情,但這並不意味着你應該這樣做。 明星導入是相當有爭議的,因為使用明星導入而不是顯式導入會使代碼更容易出錯,因為可能存在類導入沖突。 但是如果你想知道這類問題的確切答案,你就不得不問Groovy語言設計師和核心開發人員 - 他們可能毫無疑問地給你直接的答案。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.