Java或Scala:在运行时创建新类型

时间:2011-10-17 17:01:01

标签: java scala reflection

如何在运行时定义新类型?我有一个工厂方法,需要使用标记接口创建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!

5 个答案:

答案 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