使用Java :: Geci生成setter和getter

在本文中 ,我们创建了非常简单的hello-world生成器,以介绍框架以及通常如何生成生成器。 在本文中,我们将研究访问器生成器,它是在Java :: Geci的核心模块中定义的,它是商业级的,而不是仅用于演示的生成器。 即使生成器是商业级的,使用框架的服务,生成器也具有简单的代码,因此可以在文章中表示。

访问器生成器有什么作用

访问器是设置器和获取器。 当一个类有很多字段并且我们希望帮助封装时,我们将这些字段声明为private字段并创建setter和getter,每个字段一对,可以设置该字段的值(setter)并获取该字段的值(吸气剂)。 请注意,与许多初中生认为的相反,创建setter和getter并不是单独封装,而是可能是进行正确封装的工具。 同时请注意,它也可能不是正确封装的工具。 您可以在“ Joshua Bloch:有效的Java第三版”项目16中了解更多信息。

仔细阅读它。 该书说它是为Java 9更新的。该Java版本包含模块系统。 Item 16一章中没有提及,甚至该版本仍然说要使用带有setter和getter的私有成员作为公共类,在Java 9的情况下,这也意味着模块中不会导出的包中的类。

许多开发人员认为,设置者和获取者本质上是邪恶的,并且是不良设计的标志。 不要犯错! 他们不主张直接使用原始字段。 那会更糟。 他们认为您应该以更加面向对象的思维方式进行编程。 在我看来,它们是正确的,并且按照我的专业实践,我必须使用很多类来维护旧版应用程序,这些类使用包含setter和getter的旧版框架来维护旧版应用程序,这些框架是应用程序周围的编程工具所需的。 理论是一回事,现实生活是另一回事。 除非我们在添加新字段时忘记执行它们,否则不同的集成开发环境和许多其他工具(例如,生成器和获取器)会为我们生成。

设置器是一种方法,其参数与字段的类型相同,并返回void 。 (Aka不返回任何值。)按照约定set的名称,并使用首字母大写的字段名称。 对于字段businessOwner ,设置者通常是setBusinessOwner 。 设置器将字段的值设置为设置器的参数的值。

getter也是一种不带任何参数但返回参数值的方法,因此它的返回类型与字段的类型相同。 按照惯例,getter的名称是get ,再次是大写的字段名称。 这样,获取者将是getBusinessOwner

在的情况下, booleanBoolean类型fiels吸气剂具有is前缀,所以isBusinessOwner还可以的情况下,该领域是一些布尔类型的有效名称。

访问器会为其必需的所有字段生成setter和getter。

如何生成访问器

访问器生成器必须为该类的某些字段生成代码。 该生成器是Java :: Geci中过滤字段生成器的理想候选者。 过滤后的字段生成器扩展了AbstractFilteredFieldsGenerator类,并且它的process()方法为每个过滤后的字段调用一次。 除了几周前在文章中看到的常规SourceCompoundParams参数之外,该方法还将Field作为第三个参数。

AbstractFilteredFieldsGenerator类使用配置参数filter来过滤字段。 这样,对于扩展该类的每个生成器,要考虑的字段的选择都是相同的,并且生成器不必关心字段过滤:它是为它们完成的。

生成器代码的主要部分如下:

 public class Accessor extends AbstractFilteredFieldsGenerator { ... @Override public void process(Source source, Class<?> klass, CompoundParams params, Field field) throws Exception { final var id = params.get( "id" ); source.init(id); var isFinal = Modifier.isFinal(field.getModifiers()); var name = field.getName(); var fieldType = GeciReflectionTools.typeAsString(field); var access = check(params.get( "access" , "public" )); var ucName = cap(name); var setter = params.get( "setter" , "set" + ucName); var getter = params.get( "getter" , "get" + ucName); var only = params.get( "only" ); try (var segment = source.safeOpen(id)) { if (!isFinal && ! "getter" .equals(only)) { writeSetter(name, setter, fieldType, access, segment); } if (! "setter" .equals(only)) { writeGetter(name, getter, fieldType, access, segment); } } }  } 

省略号处的代码包含更多方法,我们将在后面介绍。 第一个调用是获取参数id 。 这是一个特殊参数,如果未定义,则默认params.get("id")返回是生成器的助记符。 这是唯一具有这样的全局默认值的参数。

source.init(id)的调用可确保即使生成器未向该段写入任何内容,该段也将被视为“已触摸”。 在某些情况下可能会发生这种情况,并且在编写生成器时,对于生成器要写入的任何段调用source.init(id)不会受到伤害。

该代码查看实际字段以检查该字段是否为最终字段。 如果该字段为final,则必须在创建对象时获取值,此后,设置器将无法对其进行修改。 在这种情况下,将仅为该字段创建一个吸气剂。

setter / getter生成器需要的下一项功能是字段名称,以及字段类型的字符串表示形式。 静态实用程序方法GeciReflectionTools.typeAsString()是框架中提供此功能的便捷工具。

可选的配置参数access将进入相同名称的变量,并在setter和getter的access修饰符需要不同于public 。 默认值是public ,它被定义为方法params.get()的第二个参数。 方法check()是生成器的一部分。 它检查该改性剂是正确并防止在大多数情况下产生的语法差错代码(例如:创建setter和吸气与访问修饰符pritected )。 我们将在一段时间后研究该方法。

接下来的事情是getter和setter的名称。 默认情况下是set/get +字段的大写名称,但也可以由配置参数settergetter定义。 这样,如果绝对需要,您可以拥有isBusinessOwner

最后一个配置参数only是密钥。 如果代码指定only='setter'only='getter'则仅生成setter或仅生成getter。

生成器要写入的段在try-with-resources块的开头打开,然后调用本地writeSetterwriteGetter方法。 有两种不同的方法可以从源对象打开细分。 一个正在调用open(id) ,另一个正在调用safeOpen(id) 。 第一种方法将尝试打开该段,如果在类源文件中未定义名称的段,则该方法将返回null 。 生成器可以检查无效性,并且如果已编程,则可以使用其他段名称。 另一方面,如果无法打开该段,则safeOpen()会引发GeciException 。 这是更安全的版本,以避免以后生成器中出现空指针异常。 不是很好。

请注意,仅当字段不是final且未将only配置键未配置为getter (仅)时,才写入setter。

让我们看一下这两种方法。 毕竟,这些是真正生成代码的生成器的真正核心方法。

 private static void writeGetter(String name, String getterName, String type, String access, Segment segment) { segment.write_r(access + " " + type + " " + getterName + "(){" ) .write( "return " + name + ";" ) .write_l( "}" ) .newline(); } private static void writeSetter(String name, String setterName, String type, String access, Segment segment) { segment.write_r(access + " void " + setterName + "(" + type + " " + name + "){" ) .write( "this." + name + " = " + name + ";" ) .write_l( "}" ) .newline(); } 

这些方法获取字段的名称,访问者的名称,作为字符串的字段的类型,访问修饰符字符串以及必须将代码写入的Segment 。 代码生成器不会直接写入源文件。 框架提供的segment对象用于发送生成的代码,如果需要,框架会将编写的行插入源代码中。

该段的write()write_l()write_r()方法可用于编写代码。 如果有多个参数,它们的工作方式与String.format非常相似,但是它们也关心适当的制表。 当代码调用write_r()该段将记住必须将其后的行列表在右边的四个空格处。 当代码调用write_l()该段知道制表必须减少四个字符(即使对于实际的写入行也是如此)。 它们还处理多行字符串,以便将它们全部正确制成表格。

生成的代码也应该可读。

最终的重要方法是访问修饰符检查。

 private static final Set<String> accessModifiers = Set.of( "public" , "private" , "protected" , "package" );  ... private String check( final String access) { if (!access.endsWith( "!" ) && !accessModifiers.contains(access)) { throw new GeciException( "'" +access+ "' is not a valid access modifier" ); } final String modifiedAccess; if ( access.endsWith( "!" )){ modifiedAccess = access.substring( 0 ,access.length()- 1 ); } else { modifiedAccess = access; } if ( modifiedAccess.equals( "package" )){ return "" ; } return modifiedAccess; } 

进行此检查的目的是防止程序员错误地访问access修饰符。 它检查访问修饰符是private (虽然我看不到这个的实际用例), protectedpublic还是package 。 最后一个转换为空字符串,因为包保护的访问是类方法的默认设置。 同时在配置中使用空字符串来表示程序包私有访问实际上是不可读的。

这样,如果配置pritected包含拼写错误的代码,则代码生成器将抛出异常,并拒绝生成已知包含语法错误的代码。 另一方面,访问修饰符也可以更复杂。 在极少数情况下,该程序可能需要同步的吸气剂和吸气剂。 我们不会试图自动找出类似检查字段是否可变的内容,因为这是边界情况。 但是,生成器提供了克服有限语法检查的可能性,并且仅提供任何字符串作为访问修饰符即可。 如果访问修饰符字符串以感叹号结尾,则意味着使用生成器的程序员对访问修饰符的正确性承担全部责任,并且生成器将按原样使用它(当然没有感叹号)。

剩下的是mnemoniccap方法:

 private static String cap(String s) { return s.substring( 0 , 1 ).toUpperCase() + s.substring( 1 ); } @Override public String mnemonic() { return "accessor" ; } 

框架使用mnemonic()方法来识别需要此生成器服务的源,并将其用作配置参数id的默认值。 所有生成器都应提供此功能。 另一种是cap的是大写的字符串。 我不会解释它是如何工作的。

样品使用

 @Geci ( "accessor filter='private | protected'" )  public class Contained1 { public void callMe() { } private final String apple = "" ; @Geci ( "accessors only='setter'" ) private int birnen; int packge; @Geci ( "accessor access='package' getter='isTrue'" ) protected boolean truth; @Geci ( "accessor filter='false'" ) protected int not_this; public Map<String,Set<Map<Integer,Boolean>>> doNothingReally( int a, Map b, Set<Set> set){ return null ; } //<editor-fold id="accessor" desc="setters"> //</editor-fold>  } 

该类使用Geci注释进行注释。 参数为accessor filter='private | protected' accessor filter='private | protected' ,定义将在此源文件上使用的生成器的名称并配置过滤器。 它说,我们需要私有和受保护字段的设置者和获取者。 逻辑表达式应为:“过滤字段是私有的还是受保护的”。

一些字段也有注释。 birnen将得到的只是一个二传手, truth setter和getter将被封装保护剂和吸气将被命名为isTrue() 字段not_this不会获得setter或getter,因为在字段注释中覆盖了过滤器表达式,并说: false永远不会为true ,生成器需要对其进行处理。

未注释字段apple ,它将根据类级别的配置进行处理。 它是私有的,因此将获得访问器,并且由于它是final因此将仅获得吸气剂。

之间的代码

 // <editor- fold id = "accessor" desc= "setters" > // < /editor-fold > 

将包含生成的代码。 (您必须运行代码才能看到它,我没有在这里复制它。)

摘要

在本文中,我们研究了一个生成器,它是Java :: Geci框架中真实的商业级生成器。 遍历代码,我们讨论了代码的工作方式,还讨论了编写代码生成器的其他一些更一般的方面。 下一步是使用Java :: Geci作为测试依赖项来启动一个项目,使用访问器生成器而不是IDE代码生成器(这使您忘记重新执行setter getter生成),然后也许可以创建您的拥有自己的生成器,而不仅仅是setter和getter。

翻译自: https://www.javacodegeeks.com/2019/06/generating-setters-and-getters-using-javageci.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/341298.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

1062 最简分数(PAT乙级 C++)

题目 一个分数一般写成两个整数相除的形式&#xff1a;N/M&#xff0c;其中 M 不为0。最简分数是指分子和分母没有公约数的分数表示形式。 现给定两个不相等的正分数 N1/M​1​​ 和 N​2/M​2​​ &#xff0c;要求你按从小到大的顺序列出它们之间分母为 K 的最简分数。 输…

使用xshell上传本地文件到服务器

1.查看linux上是否安装rz工具 2&#xff0c;查看安装是否完成&#xff0c;然后上传文件到服务器

ubuntu镜像下载

官方下载地址&#xff08;不推荐&#xff09; https://www.ubuntu.com/download 推荐使用 Ubuntu 20.04.4 LTS (Focal Fossa) 其余下载地址 中科大源 http://mirrors.ustc.edu.cn/ubuntu-releases/16.04/ 阿里云开源镜像站 http://mirrors.aliyun.com/ubuntu-releases/…

Dev-C++ 一直提示源文件未编译,原因及解决办法

原因 编译命令换行&#xff08;可能有的同学和我一样喜欢换行写&#xff09;&#xff0c;导致编译通不过&#xff0c;如果选择编译运行&#xff0c;便会提示"源文件未编译"。 如图 解决办法 这种写法不对&#xff0c;正确如下&#xff08;两个命令间有一个空格&…

ubuntu 下安装qemu

&#xff08;1&#xff09;安装qemu 仿真ARM需要使用qemu-system-arm&#xff0c;安装模拟器 sudo apt-get install qemu-kvm qemu-kvm-extras &#xff08;2&#xff09;下载内核镜像。以下名称叫ubuntu.iso &#xff08;3&#xff09;创建一个虚拟磁盘 sudo qemu-im…

python 怎么查看变量的数据类型

方法 type(variable_name)示例 a hello b type(a) print(b)a 10 b type(a) print(b)结果 <class str> <class int>

Valhalla项目:LW2内联类型的初步了解

我总结了最近在Valhalla LW2 项目 “ 内联类型 ”中取得的一些进展&#xff0c;这些进展最近在我的博客文章“ Valhalla LW2进度-内联类型 ”中公开了。 在这篇文章中&#xff0c;我通过针对最近发布的Valhalla Early Access Build jdk-14-valhalla 1-8&#xff08;2019/7/4&a…

QCOW2镜像格式

QEMU copy-on-write format with a range of special features, including the ability to take multiple snapshots, smaller images on filesystems that don’t support sparse files, optional AES encryption, and optional zlib compression 现在比较主流的一种虚拟化镜…

for循环简介及实例(输出九九乘法表)

for循环简介 简介 for循环是3大循环其中一种&#xff0c;相比while循环和do while循环&#xff0c;它更加灵活&#xff0c;而且完全包含了while循环的功能&#xff0c;用for语句可以解决编程中所有循环问题。 语法格式 for(语句1;表达式1;表达式2) 语句 //语句1一般用于设置…

Windows下使用net user命令管理账户

准备工作-以管理员身份运行命令提示符&#xff08;cmd&#xff09; 鼠标左键单击Windos标志或者按下键盘Windows键&#xff0c;下滑菜单&#xff0c;在Windows系统 中找到命令提示符。 2.右键&#xff0c;更多->以管理员身份运行 net user 命令用法 1.查看所有用户 net…

Java中带有NetSuite数据实体的对象关系映射(ORM)

对象关系映射&#xff08;ORM&#xff09;技术使使用关系数据源更容易&#xff0c;并且可以将逻辑业务模型与物理存储模型联系在一起。 遵循本教程&#xff0c;将与NetSuite数据的连接集成到基于Java的ORM框架Hibernate中。 您可以使用Hibernate将面向对象的域模型映射到传统的…

vmware中ubuntu虚拟机扩容

两种扩容方式&#xff1a; 重新创建一块虚拟硬盘 扩大原来的硬盘&#xff1a;如果装系统时没有进行手动分区&#xff0c;系统只有两个分区&#xff08;根分区和交换分区&#xff09;&#xff0c;这种情况我们直接扩展根分区的大小。 我们是为了解决当前用户空间不够的问题&…

pat 乙级 1021 个位数统计(C++)

题目 给定一个 k 位整数 Nd​k−1​​10​k−1​​⋯d​1​​10​1d​0(0≤d​i≤9, i0,⋯,k−1, d​k−1>0)&#xff0c;请编写程序统计每种不同的个位数字出现的次数。例如&#xff1a;给定 N100311&#xff0c;则有 2 个 0&#xff0c;3 个 1&#xff0c;和 1 个 3。 输…

该虚拟机似乎正在使用

该虚拟机似乎正在使用 点击获取所有权&#xff0c;此时虚拟机还是不能打开。 打开Vmware虚拟机虚拟磁盘文件和配置文件存放的位置 删除后缀为.lck的文件夹 然后开启此虚拟机就可以啦

PAT 乙级(Basic Level) 题解汇总(持续更新)(C++)

前言 为了准备3月份的CCF CSP认证&#xff0c;以及提升自己的编程能力和数据结构与算法基础&#xff0c;目前我坚持每天刷pat乙级题库&#xff0c;然后记录在CSDN。一则&#xff0c;希望夯实我做过的题和学到的东西&#xff1b;二则&#xff0c;希望对和我一样的小伙伴有些许帮…

反射是最重要的Java API

前几天我在想-这是最重要的Java API。 哪种SE和EE API可以使大多数Java生态系统成为可能&#xff0c;而哪些API不能刚刚被重新创建为第三方库。 正如您可能已经猜到标题一样&#xff0c;我认为它是Reflection API 。 是的&#xff0c;它不可避免地是每个项目的直接或间接的一部…

Wireshark常用过滤使用方法

过滤源ip、目的ip。 在wireshark的过滤规则框Filter中输入过滤条件。如查找目的地址为192.168.101.8的包&#xff0c;ip.dst192.168.101.8&#xff1b;查找源地址为ip.src1.1.1.1 端口过滤。 如过滤80端口&#xff0c;在Filter中输入&#xff0c;tcp.port80&#xff0c;这条规…

pat 乙级 1003 我要通过!(C++)

题目 “答案正确"是自动判题系统给出的最令人欢喜的回复。本题属于 PAT 的“答案正确”大派送 —— 只要读入的字符串满足下列条件&#xff0c;系统就输出“答案正确”&#xff0c;否则输出"答案错误”。 得到"答案正确"的条件是&#xff1a; 字符串中必…

【C】printf按8进制、10进制、16进制输出以及高位补0

#include <iostream> #include <iomanip> #include "Circle.h" // Circle class declaration file int main() { int PrintVal 9;/*按整型输出&#xff0c;默认右对齐*/printf("%d\n",PrintVal);/*按整型输出&#xff0c;补齐4位的宽度&#…

pat 乙级 1005 继续(3n+1)猜想(C++)

题目 卡拉兹(Callatz)猜想已经在1001中给出了描述。在这个题目里&#xff0c;情况稍微有些复杂。 当我们验证卡拉兹猜想的时候&#xff0c;为了避免重复计算&#xff0c;可以记录下递推过程中遇到的每一个数。例如对 n3 进行验证的时候&#xff0c;我们需要计算 3、5、8、4、…