假设我有一个class
class Original {
def originalMethod = 1
}
现在,假设我有一个实例
val instance = new Original
现在是否可以在运行时对instance
做一些事情,用不同的方法替换originalMethod
?(假定签名保持不变)
例如,现在,当调用instance.originalMethod
时,下面的代码将被称为println("test"); 1
编辑我不能打电话给new Original
。我只有它的一个现有实例,我需要修改它。
编辑2 (@Aleksey Izmailov回答)这是一个很好的解决方案,但并不是我想要的。我想更多的是在测试方面-"正常"编写类,不指定函数作为变量而不是方法
p。当我试图模仿一个Mockito间谍时,我无意中发现了这个问题
似乎你必须恢复到突变,因为你不能有新的实例和行为必须改变。下面可能是最简单的选项(REPL):
将函数存储为可变字段:
scala> class Original {
| var originalMethod = () => 1
| }
defined class Original
scala> val obj = new Original
obj: Original = Original@66ac5762
这是一个不带任何参数的函数,你需要调用apply
或()
才能得到结果。
scala> obj.originalMethod
res0: () => Int = <function0>
scala> obj.originalMethod()
res1: Int = 1 ^
用新函数替换:
scala> obj.originalMethod = () => 2
obj.originalMethod: () => Int = <function0>
现在你得到新的行为:
scala> obj.originalMethod()
res2: Int = 2
有趣的是,你不能在这个类的泛型版本中使用默认实现,因为没有默认值可以使用,除非你将其更改为Unit
或部分函数。
这是它的通用版本:
scala> class Original[T] {
| var originalMethod: () => T = null
| }
defined class Original
scala> val genImpl = new Original[Int] { originalMethod = () => 111 }
genImpl: Original[Int] = $anon$1@6b04acb2
scala> genImpl.originalMethod()
res8: Int = 111
scala> genImpl.originalMethod = () => 222
genImpl.originalMethod: () => Int = <function0>
scala> genImpl.originalMethod()
res9: Int = 222
这在JVM上是不可能的-在Java或Scala中-不是以您要求的方式。
参见:在Java中,给定一个对象,是否有可能重写其中一个方法?
使用Scala而不是Java并不会给你带来额外的优势,因为Scala中类和方法的基本原理与Java是一样的。(这样做是出于性能和互操作的考虑。)