开发过程中为了方便解析JSON数组数据,所以客户端类属性按照JSON数组数据顺序进行编写,然后通过反射分别给每个属性复制:
反射获取属性
新建一个实体类
public class InfoBean {
public String name;
public String url;
public int page;
public boolean isTest;
public AddressDTO address;
public List<LinksDTO> links;
}
通过Java的反射机制来获取类的字段列表
var obj = InfoBean()
var fields = obj.javaClass.declaredFields
for (field in fields){
Log.i(TAG,"field ${field.name}")
}
打印日志
I/MainActivity: field address
I/MainActivity: field isTest
I/MainActivity: field links
I/MainActivity: field name
I/MainActivity: field page
I/MainActivity: field url
很失望,打印的属性顺序和代码属性的顺序并不一致,因为getDeclaredFields() 方法返回的字段数组并不保证按照代码顺序排序。字段的顺序可能受到多种因素的影响,例如编译器、JVM 实现以及其他因素。
根据 Java 文档,getDeclaredFields() 方法返回的字段数组是以任意顺序返回的,没有特定的排序保证。如果需要按照特定顺序获取字段,可以使用其他方法来实现,比如通过字段名称排序或者自定义排序规则。
添加注解
我们使用自定义注解来为字段添加排序信息,并根据注解值进行排序。然而,需要注意的是,注解本身并不能直接影响字段的排序顺序,而是需要在代码中编写逻辑来实现按照注解值排序的功能。
-
自定义注解 FieldOrder
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface FieldOrder { int value(); }
在 FieldOrder.java 文件中,使用 @interface 关键字来定义注解,并为注解添加所需的元素。在这种情况下,我们需要为注解添加一个整数类型的 value 元素,用于表示字段的排序值。
-
使用自定义注解
public class InfoBean { @FieldOrder(1) public String name; @FieldOrder(2) public String url; @FieldOrder(3) public int page; @FieldOrder(4) public boolean isTest; @FieldOrder(5) public AddressDTO address; @FieldOrder(6) public List<LinksDTO> links; }
-
排序逻辑来实现字段排序
var obj = InfoBean() var fields = obj.javaClass.declaredFields fields.sortWith(compareBy { field -> field.getAnnotation(FieldOrder::class.java).value }) for (field in fields){ Log.i(TAG,"field ${field.name}") }
打印日志
I/MainActivity: field name
I/MainActivity: field url
I/MainActivity: field page
I/MainActivity: field isTest
I/MainActivity: field address
I/MainActivity: field links
完美
@Retention(RetentionPolicy.RUNTIME) 是一个用于指定注解的保留策略的元注解(meta-annotation)。它用于告诉编译器和运行时环境在何时可以访问注解。
@Retention 元注解有三个预定义的保留策略,分别是:
- RetentionPolicy.SOURCE:注解仅在源代码中保留,编译后的字节码中不包含注解信息,因此无法在运行时获取。
- RetentionPolicy.CLASS:注解在编译后的字节码文件中保留,但在运行时无法获取。这是默认的保留策略。
- RetentionPolicy.RUNTIME:注解在编译后的字节码文件中保留,并可以在运行时通过反射机制获取和使用注解信息。
@Target(ElementType.FIELD) 是另一个元注解,用于指定注解可以应用的目标元素类型。在这个例子中,@Target(ElementType.FIELD) 表示该注解可以应用在字段上。
综合起来,@Retention(RetentionPolicy.RUNTIME) 和 @Target(ElementType.FIELD) 的组合表示该注解在运行时保留,并且可以应用在字段上。这意味着我们可以在运行时通过反射获取字段上的注解信息,并根据注解值进行相应的操作,比如排序。