我經常使用Scala REPL來快速進行Java迭代和測試,但有時我想觸發某個類的私有行爲,並且必須重新編譯代碼才能使該方法可見。我希望能夠直接在REPL中調用私有Java方法,而無需更改代碼。在Scala中調用私有Java方法
我已經走到這一步:
// Calls private Java methods
// We currently define an overload for every n-argument method
// there's probably a way to do this in one method?
def callPrivate(obj: AnyRef, methodName: String) = {
val method = obj.getClass().getDeclaredMethod(methodName)
val returnType = method.getReturnType
method.setAccessible(true)
println("Call .asInstanceOf[%s] to cast" format method.getReturnType.getName)
method.getReturnType.cast(method.invoke(obj))
}
def callPrivate(obj: AnyRef, methodName: String, arg: AnyRef) = {
val method = obj.getClass().getDeclaredMethod(methodName, arg.getClass())
method.setAccessible(true)
method.invoke(obj, arg)
}
其中可用於像:
scala> callPrivate(myObj, "privateMethod", arg).asInstanceOf[ReturnedClass]
但這需要定義每個正參數方法類型近乎重複的方法(和要求外部演員,但我懷疑這是不可避免的)。有什麼辦法可以重構這個,以便一個函數可以處理任意數量的參數?
注:我使用的是Scala 2.9.1,所以我正在尋找使用Java Reflection的解決方案。歡迎使用Scala反射的答案,但不要直接解決我的問題。
非常感謝,這正是我需要的指針。我無法投射工作(調用'method.getReturnType.cast()'只是簡單地返回'Any'而不是'java.lang.Object'),但可變參數行爲現在可以工作。我冒昧地更新您的答案,並編寫當前的實施方案;如果你願意,我可以把它作爲一個單獨的答案發布。 – dimo414
還有改進的餘地。我猜想,通過泛型,您可以從類型推斷中受益,並避免在客戶端進行投射。可能你需要聲明你的方法,比如'callPrivateTyped [T](...):T',在返回之前你可以做'method.invoke(obj,parameterValues:_ *)。asInstanceOf(T)'。這樣做,你可以改變你的調用者來調用'var result:SomeType = callPrivateTyped(....)'(或者'var result = callPrivateTyped [SomeType](....)') - 我不會把它添加到我的答案是因爲仿製藥在沒有測試的情況下編寫是一件棘手的事情。 – Claudio