如何在运行时定义新类型?我有一个工厂方法,需要使用标记接口创建this.type
的新实例。标记接口在编译时未混合。我需要找到一种方法在运行时。
我正在使用Scala,但我认为答案将足够涵盖Java和Scala。
trait Fruit {
def eat: this.type with Eaten = {
getClass.getConstructors()(0).newInstance(Array()).asInstanceOf[this.type];
// somehow this needs to return a new instance of this.type with the Eaten trait
// note that "Apple with Eaten" is not a type that exists at compile-time
}
}
trait Eaten // marker interface
class Apple extends Fruit
val apple1 = new Apple
val apple2 = a.eat // should return a new Apple with Eaten instance
def eater(eaten: Eaten) = ... // this function only accepts Eaten fruit
eater(apple1) // wont compile!
eater(apple2) // will compile!
答案 0 :(得分:5)
这是不可能的。当然,有一些方法可以在运行时创建新类:只需使用任何bytecode操作library。但是this.type
不是“this
”的类,而是this
的单例类型(并且无法表达“this
的类1}}“在Scala类型签名中)!所以
def eat: this.type with Eaten = {
// may do something here, but in the end you have to return
this
}
当然,如果Apple
没有扩展Eaten
,它将无法编译,无论你在方法中做什么。通常的解决方法类似于
class Fruit[F : Manifest <: Fruit[F]] {
def eat: F with Eaten = {
val clazz = manifest[F].erasure
val result = // do your bytecode manipulations here
result.asInstanceOf[F with Eaten]
}
}
但是如果你有多个标记界面,这将不起作用:
val apple = new Apple // Apple
val washed = apple.wash // Apple with Washed
val eaten = washed.eat // Apple with Eaten, but no longer Washed!
答案 1 :(得分:2)
我不确定你要解决的是什么样的问题,但也许你可以使用像类型构造函数这样的特性,而不是实现特性,所以Eaten就像
class Eaten[T]
和Apple.eat返回
Eaten[Apple]
答案 2 :(得分:1)
JDK6将允许您编译实际的Java代码。见http://www.java2s.com/Code/Java/JDK-6/CompilingfromMemory.htm
或者(特别是如果你想创建一个实现接口的类),你应该看看:java.lang.reflect.Proxy
,它可以让你做这样的事情:
InvocationHandler handler = new MyInvocationHandler(...);
Class proxyClass = Proxy.getProxyClass(
Foo.class.getClassLoader(), new Class[] { Foo.class });
Foo f = (Foo) proxyClass.
getConstructor(new Class[] { InvocationHandler.class }).
newInstance(new Object[] { handler });
请注意JMock之类的内容也非常简单。
答案 3 :(得分:1)
好吧,在Scala中,你可以使用名为implicit conversions的东西。但是在Java中没有相同的东西。
您的代码看起来像:
implicit def fruit2eaten(fruit: Fruit) = // some way of creating an Eaten from a fruit here.
答案 4 :(得分:0)
据我所知(虽然不多)scala不是动态语言,但它更像是一种函数式语言。现在在groovy中 - 它是一种动态语言,你可以在字符串或文本文件中定义一个类,并在运行时对其进行评估,但我不相信这些东西在scala中是可能的。
修改:一些动态功能是coming to scala