java自动生成类

如果您今年访问过JavaOne,您可能已经参加了我的演讲“如何从数据库生成定制的Java 8代码”。 在那次演讲中,我展示了如何使用Speedment Open Source工具包使用数据库作为域模型来生成各种Java代码。 我们没有时间要考虑的一件事是,Speedment不仅使代码生成变得更容易,它本身也由生成的代码组成。 在本文中,我将向您展示我们已经设置了Speedment来生成许多类的专用版本,以减少系统中性能关键部分的内存占用。

背景

您可能知道,Java有许多内置值类型。 这些是字节,短裤,整数,长号,浮点数,双打,布尔值和字符。 基本值类型与普通对象的不同之处主要在于它们可以直接在内存堆栈上分配,从而减轻了垃圾回收器的负担。 不从Object继承的一个问题是它们不能被放入集合中或作为参数传递给不带包装而接受对象参数的方法。 因此,典型的包装类为“整数”,“双精度”,“布尔”等。

包装值类型并不总是一件坏事。 如果可以安全地用原始值替换包装类型,则JIT(即时)编译器非常擅长优化包装类型,但这并不总是可行的。 如果这种情况发生在代码的性能关键部分(如内部循环)中,则会严重影响整个应用程序的性能。

这就是我们从事Speedment时发生的事情。 我们有特殊的谓词和函数,其中包含有关其目的的元数据。 需要在一个内部循环内非常快速地分析该元数据,但是由于大多数元数据都包装在通用类型中以便可以动态实例化它们的事实,我们感到放慢了速度。

解决此问题的常用方法是为包含包装器类型的类创建多个“专业化”类。 除了使用原始值类型之一而不是通用(仅对象)类型之外,这些专业化与原始类相同。 专门化的一个很好的例子是Java 8中存在的各种Stream接口。除了“ Stream”之外,我们还具有“ IntStream”,“ DoubleStream”和“ LongStream”。 这些专业化对于其特定的值类型更为有效,因为它们不必依赖于对象中的包装类型。

专业化类的问题在于它们为系统增加了很多样板。 假设需要优化的零件由20个组件组成。 如果要支持Java拥有的所有8种原始变体,您突然会拥有160个组件。 那要维护很多代码。 更好的解决方案是生成所有额外的类。

基于模板的代码生成

高级语言中最常见的代码生成形式是基于模板的。 这意味着您编写一个模板文件,然后根据要生成的内容进行关键字替换来修改文本。 Maven原型或Thymeleaf是很好的例子。 一个好的模板引擎将支持更高级的语法,例如重复节,表达条件等。如果要使用模板引擎生成专业化类,则可以将所有出现的“ int”,“ Integer”,“ IntStream”替换为特定的像“ $ {primitive}”,“ $ {wrapper}”,“ $ {stream}”之类的关键字,然后指定要与每种新值类型相关联的单词词典。

基于模板的代码生成的优点是易于设置和维护。 我认为大多数阅读本文的程序员都可能会想出如何轻松编写模板引擎的方法。 缺点是模板难以重用。 假设您有一个专门的基本模板,但是您希望浮动类型也有其他方法。 您可以使用条件语句解决此问题,但是如果您希望该其他方法也可以在其他地方存在,则需要复制代码。 通常需要重复的典型代码示例是hashCode()-methods或toString()。 这是基于模型的代码生成更强大的地方。

基于模型的代码生成

在基于模型的代码生成中,您可以在要生成的代码上构建一个抽象语法树,然后使用合适的渲染器渲染该树。 可以根据所使用的上下文来对语法树进行更改,例如,通过添加或删除实现特定接口的方法来进行更改。 其主要优点是更高的灵活性。 您可以动态地采用现有模型并操纵要包括的方法和字段。 不利的一面是,基于模型的代码生成通常需要更长的时间来设置。

案例研究:速度场发生器

在Speedment,我们开发了一个名为CodeGen的代码生成器,它使用基于模型的方法为所有原始值类型自动生成字段专业化。 每个构建总共生成大约300个类。

Speedment CodeGen使用围绕面向对象设计的基本概念构建的抽象语法树。 您具有用于构建域模型的类,接口,字段,方法,构造函数等。 在方法级别以下,您仍然需要编写模板代码。 要定义一个新的主类,您可以编写:

import com.speedment.common.codegen.model.Class; // Not java.lang.Class...Class createMainClass() {return Class.of("Main").public_().final_().set(Javadoc.of("The main entry point of the application").add(AUTHOR.setValue("Emil Forslund")).add(SINCE.setValue("1.0.0"))).add(Method.of("main", void.class).public_().static_().add(Field.of("args", String[].class)).add("if (args.length == 0) " + block("System.out.println(\"Hello, World!\");") + " else " + block("System.out.format(\"Hi, %s!%n\", args[0]);")));
}

这将生成以下代码:

/*** The main entry point of the application.* * @author Emil Forslund* @since  1.0.0*/
public final class Main {public static void main(String[] args) {if (args.length == 0) {System.out.println("Hello, World!");} else {System.out.format("Hi, %s!%n", args[0]);}}
}

不必一次生成整个模型。 例如,如果我们想自动生成toString()方法,则可以将其定义为单个方法。

public void generateToString(File file) {file.add(Import.of(StringBuilder.class));file.getClasses().stream().filter(HasFields.class::isInstance).filter(HasMethods.class::isInstance).map(c -> (HasFields & HasMethods) c).forEach(clazz -> clazz.add(Method.of("toString", void.class).add(OVERRIDE).public_().add("return new StringBuilder()").add(clazz.getFields().stream().map(f -> ".append(\"" + f.getName() + "\")").map(Formatting::indent).toArray(String[]::new)).add(indent(".toString();"))));
}

在这里,您可以看到特质模式如何用于从逻辑中抽象出底层实现。 该代码将对Enum和Class均适用,因为两者均实现了特征“ HasFields”和“ HasMethods”。

摘要

在本文中,我解释了什么是专业化类,以及为什么有时必须使用它们来提高应用程序关键部分的性能。 我还向您展示了Speedment如何使用基于模型的代码生成来自动生成专业化类。 如果您有兴趣自己使用这些工具生成代码,请继续并在GitHub上查看生成器的最新版本 !

翻译自: https://www.javacodegeeks.com/2016/11/auto-generate-optimized-java-class-specializations.html

java自动生成类

java自动生成类_自动生成优化的Java类专业知识相关推荐

  1. C# - 类_使用新成员隐藏基类成员

    1 using System; 2 3 namespace 类_使用新成员隐藏基类成员 4 { 5 // 基类 : Animal 6 public class Animal 7 { 8 // 基类的普 ...

  2. mysql怎么生成可执行文件_查询mysql数据库的java程序在myeclipse上运行正常,但生成可执行文件后查询不出结果。问题出在哪儿呢?...

    展开全部 你所说的可执行文件,就是jar包吗?e69da5e6ba903231313335323631343130323136353331333337613164 自己生成的jar文件,执行需要指明所 ...

  3. java中的随机生成算法_随机生成算法的java代码太复杂了

    public static Integer[] generateRandomArray(int n, int rangeL, int rangeR) { assert rangeL <= ran ...

  4. java如何创造一个整数的类_【技术干货】Java 面试宝典:Java 基础部分(1)

    原标题:[技术干货]Java 面试宝典:Java 基础部分(1) Java基础部分: 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语法,集合的语法,io 的 ...

  5. java编译器jdk版本_以编程方式确定Java类的JDK编译版本

    java编译器jdk版本 当需要确定使用哪个JDK版本来编译特定的Java .class文件时, 通常使用的方法是使用javap并在javap输出中查找列出的"主要版本". 我在我 ...

  6. java+cas实现类_像宝石一样的Java原子类-基于CAS实现

    主要内容 1. 线程同步标准的处理方法:上锁 2. 锁的问题 3. 硬件同步原语CAS 4. 使用CAS实现计数器 5. Lock-free和 wait-free 算法 6. Atomic原子变量类 ...

  7. java rhino js类_让Rhino JS看Java类

    我正在玩 Rhino,我已经成功使用了stdlib中的Java类,但没有使用我编译的Java代码. 例如,这工作正常: print(new java.util.Date()); 但是使用NanoHTT ...

  8. spring 加载java类_在Spring中基于Java类进行配置的完整步骤

    在Spring中基于Java类进行配置的完整步骤 发布于 2020-7-7| 复制链接 基于Java配置选项,可以编写大多数的Spring不用配置XML,下面 前言JavaConfig 原来是 Spr ...

  9. java 根据类名示例化类_如何使用示例从Java中的类路径加载资源

    java 根据类名示例化类 Java中的类路径不仅用于加载.class文件,而且还可以用于加载资源,例如属性文件,图像,图标,缩略图或任何二进制内容. Java提供了API来将这些资源读取为Input ...

  10. java引用公共类_使用键引用从Java公共类获取值 - java

    我们有一个Java公共类, public class Test { public class ob1 { public static final String test = "T1T1&qu ...

最新文章

  1. WCF契约的简单介绍(服务契约 数据契约 消息契约)
  2. TCP/IP / UDP 头
  3. 势能线段树(均摊分析)
  4. html调用python_flask之模板html中调用python函数方法
  5. Linux怎么取消软链接
  6. 剑三 服务器维护,11月15日服务器例行维护公告 补偿部分服务器
  7. Winform 五种常用对话框控件的简单使用
  8. matlab 正版下载,matlab软件正版
  9. vue实现横向时间轴组件
  10. shell脚本实战之坦克大战小游戏
  11. java回顾:MyBatis开发、配置、标签、封装会话工具
  12. Android根据输入法的状态隐藏和关闭输入法
  13. 一起来学java!!! day003 流程控制01 你掉了金斧头还是银斧头?
  14. 前端开发中表格table单元格高度或者行高的设置
  15. 专访 | 快手王仲远:技术创业不要拿着锤子找钉子
  16. 清北学堂2019.8.7
  17. Java-汉字字符串转拼音,包括首字母和全拼
  18. 16.【Linux】window和linux下文件格式相互转换
  19. 补漏之XML配置文件基本使用
  20. 144.如何评价个性化推荐系统的效果-1

热门文章

  1. 洛谷P1173:[NOI2016] 网格(tarjan、离散化)
  2. 理解至上:二叉堆与优先队列详细用法
  3. Loj#116-[模板]有源汇有上下界最大流
  4. jzoj2292-PPMM【模拟,堆】
  5. jzoj1213-棋盘上的士兵【状压dp】
  6. P3980 NOI2008志愿者招募
  7. DevOps通用及版本控制面试题
  8. 学习java多线程,这必须搞懂的这几个概念
  9. Java生成随机数的几种高级用法
  10. Hibernate框架之入门配置