当前位置: 首页 > 面试题库 >

Java是否可以进行静态元编程?

柴凌
2023-03-14
问题内容

我是C ++中静态元编程的迷。我知道Java现在有了泛型。这是否意味着在Java中可以进行静态元编程(即,编译时程序执行)?如果是这样,任何人都可以推荐任何好的资源,以便在其中可以了解更多的信息?


问题答案:

这个问题已经有10多年的历史了,但是我仍然缺少一个答案。这是: 是的 ,但不是 因为 泛型,并且注释与C ++完全相同。

从Java 6开始,我们具有可插入注释处理api。静态元编程是(正如您在问题中已经提到的那样)

编译时程序执行

如果您了解元编程,那么您也知道这不是真的,但是为了简单起见,我们将使用它。请看看这里,如果你想了解更多关于一般的元编程。

在读取.java文件之后但在编译器将字节码写入.class文件之前,编译器将调用可插入注释处理api。(我有一个消息源,但是我找不到了。也许有人可以在这里帮助我?)。

它允许您在编译时使用纯Java代码进行逻辑处理。但是,您所编码的世界完全不同。没有特别的坏,没有什么,只是有所不同。您正在分析的类尚不存在,并且您正在处理这些类的元数据。但是编译器在JVM中运行,这意味着您也可以正常创建类和程序。但此外,您可以分析泛型,因为
类型擦除 之前 会调用我们的注释处理器。

关于Java中静态元编程的主要要点是,您提供元数据(以注释的形式),并且处理器将能够找到所有带注释的类来对其进行处理。在(更简单的)示例可以在Baeldung上找到,在该示例中形成了一个简单的示例。我认为,这是一个很好的入门资源。如果您了解这一点,请尝试使用Google自己。有很多好的资源,这里有很多。还可以看看利用注释处理器的Google
AutoService
,它消除了创建和维护服务文件的麻烦。如果要创建类,我建议您看一下JavaPoet。

遗憾的是,此API不允许我们操纵源代码。但是,如果您确实愿意,应该看看Lombok项目。他们这样做,但是不支持。

为什么如此重要(进一步阅读感兴趣的人)

TL; DR: 这让我感到莫名其妙,为什么我们不使用静态元编程而不使用动态元编程,因为它具有许多优点。

大多数开发人员看到了“动态和静态”,并立即得出结论:动态更好。毫无疑问,static对开发人员有很多负面的含义。但是在这种情况下(特别是对于Java),这是完全相反的方法。

动态元编程需要反思,这有一些
主要
缺点。有很多。简而言之:性能,安全性和设计。

静态元编程(即注释处理)使我们可以与编译器相交,该编译器已经完成了我们尝试使用反射完成的大部分工作。我们还可以在此过程中创建类,然后将它们再次传递给注释处理器。然后,您可以(例如)生成类,这些类通常需要使用反射来完成。此外,我们可以实现“快速失败”系统,因为我们可以将错误,警告等信息告知编译器。

总结并尽可能多地进行比较:让我们想象一下Spring。Spring尝试在运行时查找所有带组件注释的类(可以在编译时使用服务文件进行简化),然后生成某些代理类(在编译时就已经可以完成)并解析Bean依赖项(再次,我们已经可以在编译时完成)。杰克·沃顿(Jake
Whartons)谈到了Dagger2,他在其中解释了为什么他们转向静态元编程。我仍然不明白为什么像Spring这样的大公司不使用它。

简而言之,这篇文章旨在全面解释这些差异以及为什么static会更强大。如果您愿意,我目前正在为此进行演示。如果您有兴趣并说德语(对此感到抱歉),则可以查看我的网站。在那里您可以找到一个演示文稿,该演示文稿试图解释45分钟内的差异。虽然只有幻灯片。



 类似资料:
  • 问题内容: 给定仅在程序设置中使用的假设实用程序类: 不再使用myObject时会对其进行垃圾回收,还是在程序的生命周期内始终存在? 问题答案: 加载类时,不能选择静态变量进行垃圾回收。当各自的类加载器(负责加载此类)本身被收集为垃圾时,可以收集它们。 查看JLS第12.7节卸载类和接口 仅当垃圾回收器可以回收定义的类加载器时,才可以卸载类或接口。引导加载器加载的类和接口可以不卸载。

  • 问题内容: 是否可以构建一个HelloWorld.lib并使用JNI将其加载到Java应用程序中?还是仅适用于共享库? 我在JNI文档中找不到明确的答案,没有引用“静态库”。 问题答案: 它必须是一个动态库。幸运的是,您可以从静态库中构建一个动态库。

  • 问题内容: 我正在尝试在计算机上运行以下代码,但是它没有执行任何操作,也没有显示任何错误。 有人可以帮帮我吗?顺便说一句,我正在使用Java 7。 问题答案: 如果将-放在-block 的末尾,它将在Java 6及更低版本中正确运行(没有有效的!)。这是因为该块是 在搜索有效方法 之前 执行的,因此,如果您在静态块的末尾退出程序,则不会收到任何错误。 但是, 此行为在Java 7中已更改。现在,您

  • 问题内容: 如果是跑它运行在您的文件结尾通过运行启动格式的功能和使用(* T testing.T)模块。我想知道文件中的每个功能是同时运行还是确定地分别运行每个功能?是否为每个人创建一个执行例程?如果确实为每个例程创建了一个go例程,是否可以某种方式监视go例程?是否有可能做类似的事情并为每个实例获取一个实例并对其进行监控,诸如此类? 注意:这个问题假设您使用go(测试)随附的测试框架。 问题答案

  • 问题内容: 静态变量只有实例(也就是说,它们是类的一部分)。例如:Math.pi 有什么办法可以有多个静态变量实例吗?我听说有一些与Classloader相关的东西吗? 问题答案: 如果发现需要一个静态变量的多个实例,则强烈表明您不应该首先使用静态变量。 是的,如果同一类加载到不同的类加载器中,则该类的每个副本将具有其自己的静态变量。但是,唯一可以静态引用这些静态变量的代码将是由同一类加载器加载的

  • 我正在尝试使用柯特林 V1.2.70、Gradle V4.10.1 和 Java 11。使用 gradle 编译项目时,出现错误,指出“未知的 JVM 目标版本:11。支持的版本:1.6,1.8“。 Kotlin 编译器是否支持 Java 11(生成与 Java 11 JVM 兼容的代码)?如果是这样,如何使用渐变配置?