我使用以下代码实例化scala对象。这有效,但似乎有一个问题:println
打印出两次,每次都有另一个哈希码。
import scala.reflect.runtime.universe._
import scala.reflect.runtime.{universe => ru}
object Test2 { println("init"+hashCode())}
val mirror = ru.runtimeMirror(getClass.getClassLoader)
val m = ru.typeOf[Test2.type].members.filter(_.isConstructor).head.asMethod
val m2 = mirror.reflectClass(typeOf[Test2.type].typeSymbol.asClass)
val cm = m2.reflectConstructor(m)
val e = cm.apply()
结果:
init472467991
init2051378291
e: Any = Test2$@7a458c73
hashCode
的{{1}}等于后者(2051378291)。我想知道为什么这是因为据我所知,应该只有一个?
编辑:使用scala版本2.12.4
答案 0 :(得分:3)
您正在调用类的私有构造函数。 Scala反射允许它。当你调用一个构造函数时,你会得到一个新实例。
在普通Java中制作单例实际上非常困难,因为除了使用new Something
之外,还有一些方法可以构建实例。例如,反序列化might not call any constructors besides one of Object。并且sun.misc.Unsafe#allocateInstance
可以在不调用任何构造函数代码的情况下召唤任何类sans java.lang.Class
的新实例。
Scala object
做了一些工作,以确保您在正常使用期间不会意外创建第二个实例(例如,它隐藏构造函数并处理反序列化),但它无法保护您来自故意创建一个。当你开始使用反射时,你就是这么做的。
甚至Java enum
也可以在运行时使用反射进行实例化。你不能直接在枚举上调用Class#newInstance
(实现禁止它),但了解一些内部细节可以帮助你**
import java.nio.file.StandardOpenOption // first std enum I could remember for a quick dirty sample
val ctor = classOf[StandardOpenOption].getDeclaredConstructors.head
val aac = ctor.getClass.getDeclaredMethod("acquireConstructorAccessor")
aac.setAccessible(true) // unlimited power!
val ctorAccess = aac.invoke(ctor)
val newInstanceCall = ctorAccess.getClass.getDeclaredMethod("newInstance", classOf[Array[AnyRef]])
newInstanceCall.setAccessible(true)
// note that it does not throw ClassCastException, so it's a fine instance
val uhOh = newInstanceCall.invoke(ctorAccess, Array("UhOh", 42)).asInstanceOf[StandardOpenOption]
assert(uhOh.name == "UhOh")
assert(uhOh.ordinal == 42)
(interactive version @ Scastie)
获得"默认"例如,您can access使用反射命名为MODULE$
的公共静态字段。您还可以run whole scala compiler at runtime
对于你来说,不管你想要实现什么,不要依赖反思,这可能是你最好的选择。
顺便说一句,有可能让ScalaReflectionException
尝试在工作表模式下运行IntelliJ工作表或Scastie中的代码,因为这些东西用main方法将代码包装在另一个对象中
*仅在少数版本的HotSpot JVM上测试
**请不要在任何严肃的代码中执行此操作!我只是用它来证明一点。这也没用,因为它不会更改values
或valueOf
。是的,我只在JDK8附带的HotSpot上查看过它。