我制作的程序可以使用反射生成类,枚举和接口的源代码,但是我对Enum生成有问题。
我的EumTest课程
public enum EnumTest{
a,b;
private String r;
private EnumTest(){
}
private void some(){
}
public int[] some2(int[] b){
return b;
}
}
生成枚举文件的方法
private void generateEnum(Class<?> cls,PrintWriter writer) {
this.writePackage(cls, writer);
this.writeAnnotations(writer, cls.getDeclaredAnnotations());
writer.write(Modifier.toString(cls.getModifiers())+ " enum " + cls.getSimpleName());
this.writeImplementation(cls, writer);
writer.write("{");
this.writeNewLine(writer);
Object[] cons = cls.getEnumConstants();
for (int i = 0; i < cons.length; i++) {
writer.write(cons[i].toString());
if(i != cons.length - 1)
writer.write(",");
}
writer.write(";");
this.writeNewLine(writer);
this.writeFields(cls, writer);
this.writeConstructors(cls, writer);
this.writeMethods(cls,writer);
writer.write("}");
}
结果是这个新的枚举
package metaprogramovanie.test;
public final enum EnumTest{
a,b;
private java.lang.String r;
private static final metaprogramovanie.test.EnumTest[] $VALUES;
private EnumTest(java.lang.String arg0,int arg1){
}
public static metaprogramovanie.test.EnumTest[] values(){
return null;
}
public static metaprogramovanie.test.EnumTest valueOf(java.lang.String arg0){
return null;
}
private void some(){
}
public int daco(int arg0){
return 0;
}
}
正如您所看到的,有som错误。例如,Modifier生成FINAL和枚举不能是final,接下来有更多的方法和字段,构造函数有参数...
构造函数生成
private void writeConstructors(Class<?> cls, PrintWriter writer){
Constructor[] cons = cls.getDeclaredConstructors();
for (Constructor constructor : cons) {
this.writeAnnotations(writer, constructor.getDeclaredAnnotations());
writer.write(Modifier.toString(constructor.getModifiers()) + " " + cls.getSimpleName());
this.writeParameters(writer,constructor.getParameters());
writer.write("{");
this.writeNewLine(writer);
writer.write("}");
this.writeNewLine(writer);
}
}
字段生成
private void writeFields(Class<?> cls, PrintWriter writer){
Field[] atr = cls.getDeclaredFields();
for (Field field : atr) {
if(field.isEnumConstant()){
System.out.println("JE");
}
else{
this.writeAnnotations(writer, field.getDeclaredAnnotations());
writer.write(Modifier.toString(field.getModifiers())+" " + field.getType().getTypeName()+ " " + field.getName());
if(Modifier.isStatic(field.getModifiers())){
try{
Object value = field.get(null);
writer.write(" = " + this.getFieldValue(field));
}catch(IllegalAccessException ex){
}
}
writer.write(";");
this.writeNewLine(writer);
}
}
this.writeNewLine(writer);
}
方法生成
private void writeMethods(Class<?> cls, PrintWriter writer){
Method[] methods = cls.getDeclaredMethods();
for (Method met : methods) {
this.writeAnnotations(writer, met.getDeclaredAnnotations());
writer.write(Modifier.toString(met.getModifiers())+" "+met.getReturnType().getTypeName() +" "+ met.getName());
this.writeParameters(writer, met.getParameters());
writer.write("{");
this.writeNewLine(writer);
if(!met.getReturnType().equals(Void.TYPE)){
this.writeMethodBody(writer,met);
}
this.writeNewLine(writer);
writer.write("}");
this.writeNewLine(writer);
}
this.writeNewLine(writer);
}
如果你有任何想法如何获得可以编译的枚举。
答案 0 :(得分:1)
以下是您获得所有额外资料的原因。
枚举是使用由编译器合成的大量代码实现的,因此&#34;在幕后&#34;它们的行为与Java语言规范指定的一样,不需要对JVM进行彻底更改。
例如,Java Language Specification表示:
enum
隐含final
,除非有身体的常量。enum
隐式声明方法values()
和valueOf(String)
。出于这个原因,你获得了final
的{{1}}修饰符,你得到了两个额外的方法。
此外,编译器会综合一些代码来帮助有效地实现一些必需的内容。例如,要由方法EnumTest
复制和返回的数组源放在一个名为values()
的合成字段中。它在枚举的初始化时填充,然后只要调用$VALUES
就可以复制它。
此外,为了正确初始化常量,编译器会为每个构造函数添加两个隐藏参数。因此,如果你有一个空的构造函数,在幕后它实际上有两个参数 - 常量的名称和它的序数。如果你有一个带有一个参数的构造函数,那么在幕后它将有3个参数。
当您拥有自己的实体常量时,会创建其他合成代码。
编译器完成的所有这些后续实现都是在JLS中记录的不,并且基本上由任何编译器决定如何实现。只要enum由于编译器生成的任何代码而正确运行,就可以以它选择的任何方式自由生成它。
克服遇到的一些问题的提示:
不使用values()
打印Modifier.toString(cls.getModifiers())
修饰符,而是使用
enum
这将排除输出中的Modifier.toString(cls.getModifiers() & ~ Modifier.FINAL & ~ Modifier.ABSTRACT)
修饰符以及final
修饰符,如果您向abstract
添加抽象方法(并处理常量实体,则会显示)你到目前为止还没做过的事情。)
Field.isSynthetic()
方法检查字段是否由编译器合成,并且不输出此方法返回enum
的字段。这将摆脱true
字段。$VALUES
和values()
不属于合成方法,如果对它们使用valueOf(String)
,则会返回false。因此,您只需检查枚举中找到的每种方法即可。如果它是这两种方法之一,使用JLS中指定的签名和返回类型,请跳过它们,不要输出它们。棘手的部分是摆脱每个构造函数的两个附加参数。基本上,当您遍历构造函数参数时,可以跳过前两个参数。但是,请记住,这只适用于Oracle编译器生成的代码,并且在将来的版本或任何其他编译器中无法保证!