从2.11版开始,scala反射功能(尤其是wrt注释)的(当前)状态是什么? - java

Improve this question

scala似乎是JVM Universe的绝佳补充。它使我想起了嵌套在JVM世界中的C ++,C#和Swift的奇怪混合体。

但是,由于缺少或过时的文档,许多scala的功能可能无法访问。

就其反射能力而言,尤其如此。

例如,我正在评估是否有可能使用scala注释在运行时或编译时扩充scala类。我正在使用最新的scala版本2.11。举例来说,假设我创建了一个case class SimpleAnnotation() extends StaticAnnotation。我想在运行时找到带有该批注的所有case class

这可能是最典型且最原始的注释用例。

在C#和Java中,在运行时确定给定类是否带注释是相对简单的。这是一种规范的用例,带有规范的答案。但是在scala中,我不清楚要实现这种行为应该做什么,甚至不清楚是否可行。特别是,在扫描了一些有关scala注释和反射的先前材料之后,我感到纳闷:

这可能吗?
这仅在运行时或编译时可行吗?
这仅在scala 2.10版之前或之后才可能吗?
这只能在scala类上使用Java注释吗?
为什么getClass[AnnotatedClass].getAnnotations返回这些看似乱码的信息?
为什么在scala中似乎将宏和反射混为一谈?

感谢任何指导...我敢肯定,我不是唯一一个感到困惑的人。

java参考方案

反射和宏共享许多API,因为它们基本上是同一件事:元编程。您可以生成和执行代码,必须反映类型等等。当然存在一些差异:在编译时,您无法反映运行时实例;在运行时,您无法访问方法的内部结构,作用域以及在编译期间删除的其他信息。

这两个API仍处于试验阶段,将来可能会在某些部分进行更改,但是它们非常有用,而且文档记录也很好。 Scala是一种通用语言,它们比Java中的API复杂得多。

该文档为您带来了很多:

http://www.scala-lang.org/api/2.11.7/scala-reflect/

http://www.scala-lang.org/api/2.11.7/scala-compiler/

http://docs.scala-lang.org/overviews/(页面底部)

getClass[AnnotatedClass].getAnnotations仅为您提供Java注释,要获取Scala注释,您必须获取Scala类型,而不是仅获得类。

可以在运行时和编译时访问反射,但是有三种注释:

仅在代码中的纯注释:可以从编译单元中的宏访问这些注释,在该宏中调用该宏,该宏可以访问AST
在编译单元上共享的StaticAnnotation:可以通过scala反射api访问这些
ClassfileAnnotations:这些代表存储为Java注释的注释。如果要通过Java Reflection API访问它们,则必须使用Java定义它们。

这是一个例子:

@SerialVersionUID(1) class Blub

现在,我们可以通过以下方式获取注释:

import scala.reflect.runtime.universe._
val a = typeOf[Blub].typeSymbol.annotations.head

我们实际上得到的不是注释的实例。运行时环境只给我们字节代码中写的内容:生成注释的scala代码。您可以打印出所获得的AST:

showRaw(a.tree)

现在,这已经是一个非常复杂的结构,但是我们可以使用模式匹配来分解它:

val Apply(_, List(AssignOrNamedArg(_,Literal(Constant(value))))) = a.tree
val uid = value.asInstanceOf[Long]

对于非常简单的注释,这是可以的(但是我们可以用Java编写注释,并依靠JVM为我们创建实例)。如果我们实际上想评估该代码并生成注释类的实例怎么办? (对于@SerialVersionUID,这对我们没有多大帮助,因为该类实际上不提供对id的访问权限。)我们也可以这样做:

case class MyAnnotation(name: String) extends annotation.ClassfileAnnotation

@MyAnnotation(name = "asd")
class MyClass

object MyApp extends App {
  import reflect.runtime.universe._
  import scala.reflect.runtime.currentMirror
  import scala.tools.reflect.ToolBox
  val toolbox = currentMirror.mkToolBox()
  val annotation = typeOf[MyClass].typeSymbol.annotations.head
  val instance =  toolbox.eval(toolbox.untypecheck(annotation.tree))
        .asInstanceOf[MyAnnotation]
  println(instance.name)
}

请注意,这将调用编译器,这会花费一些时间,特别是如果您是第一次使用编译器。复杂的元编程实际上应该在Scala的编译时完成。 Java中的许多工作仅在运行时完成,因为您只能进行运行时元编程(嗯,有注释处理器,但它们的局限性更大)。

java:继承 - java

有哪些替代继承的方法? java大神给出的解决方案 有效的Java:偏重于继承而不是继承。 (这实际上也来自“四人帮”)。他提出的理由是,如果扩展类未明确设计为继承,则继承会引起很多不正常的副作用。例如,对super.someMethod()的任何调用都可以引导您通过未知代码的意外路径。取而代之的是,持有对本来应该扩展的类的引用,然后委托给它。这是与Eric…

Java-如何将此字符串转换为日期? - java

我从服务器收到此消息,我不明白T和Z的含义,2012-08-24T09:59:59Z将此字符串转换为Date对象的正确SimpleDateFormat模式是什么? java大神给出的解决方案 这是ISO 8601标准。您可以使用SimpleDateFormat simpleFormat = new SimpleDateFormat("yyyy-MM…

Java-固定大小的列表与指定初始容量的列表之间的差异 - java

我在理解这一点上遇到了问题。当我们做 List<Integer> list = Arrays.asList(array); 我们不能在该列表上使用添加,删除之类的方法。我知道Arrays.asList()返回固定大小的列表。我不明白的是,如果我们创建一个具有指定初始容量的列表,例如List<Integer> list2 = new A…

从方法返回数组-Java - java

private static Coordinate[] getCircleCoordintaes() { Coordinate coordinates[] = {new Coordinate(0, 0)}; return coordinates; } 以上程序工作正常。在上面的程序中,返回的坐标数组首先初始化了数组使用这条线Coordinate coordi…

Java Swing SearchBox模型 - java

我需要使用Java Swing的搜索框,如果单击任何建议,当输入字母时它将显示来自数据库的建议,它将执行一些操作。如果有可能在Java swing中,请提供源代码提前致谢 java大神给出的解决方案 您可以使用DefaultComboBoxModel,输出将是这样。Try this在此代码中,您将找到countries数组,因此您需要从数据库中获取此数组。