Java经典语法:transient关键字使用总结

Java经典语法:transient关键字使用总结

最近在看HashMap源代码的时候,发现链表table数组采用了transient关键字,笔者当时感觉对transient关键字很陌生但又似曾相识,哪里用到过?所以对java关键字 transient总结了下。

Java经典语法:transient关键字使用总结

Java关键字:transient的定义

简单来说,被transient修饰过的成员属性,不能被序列化。

我们以查询某个产品API接口为例,通过产品ID,查询返回一个产品对象,通过json序列化后把json数据返回给前端。

public class Product {
 private int amounts;
 private int price;
 private int sum;
}
json
{"amounts":3,"price":2,"sum":6}

Java关键字:transient的约定

约定一、只能修饰变量
而不能修饰方法和类。注意,本地变量是不能被transient关键字修饰的。

约定二、被transient关键字修饰过的属性不能被序列化
也就是说,被transient修饰过的属性,在对对象序列化后,是无法访问到该属性的。

约定三、静态变量不管有无被transient修饰过,不能被序列化

Java关键字:transient使用场景

对象属性推导
如果一个对象的属性值,可以通过其他属性或者方法推理出来的,那么没该属性没必要被序列化了。

例如有个产品对象(Product)包括价格、数量、总价三个字段,那么总价可以通过价格乘以数量推导出来。

@Data
static class Product {
 private int amounts;
 private int price;
 private transient int sum;
}
public static void main(String[] args) {
 Product p = new Product();
 p.setAmounts(3);
 p.setPrice(2);
 p.setSum(p.getAmounts() * p.getPrice());
 String json = new Gson().toJson(p);
 System.out.println(json);
}

输出结果:

 {"amounts":3,"price":2}

我们看到,sum属性被transient修饰后,不会被Gson序列化输出。
我们来分析下Gson序列化过程:Gson序列化源码分析,首先调用toJson方法,传入Product对象:

new Gson().toJson(p)

根据传入的对象,获取对象的class类型:typeOfSrc,找到对应的对象解析适配器工厂

toJson(Object src, Type typeOfSrc, JsonWriter writer)

TypeAdapter adapter = getAdapter(TypeToken.get(typeOfSrc));
for (TypeAdapterFactory factory : factories) {
 // 得到ReflectiveTypeAdapterFactory
 TypeAdapter candidate = factory.create(this, type);
}

通过适配器ReflectiveTypeAdapterFactory工厂的create方法,我们找到getBoundFields方法,这个方法做了两件事情
1、剔除被transient关键字修饰过的属性。
2、筛选出可序列化的属性

new Adapter(constructor, getBoundFields(gson, type, raw));
for (Field field : fields) {
 boolean serialize = excludeField(field, true);
 boolean deserialize = excludeField(field, false);
 ...
}

通过excludeField方法,剔除被transient修饰过的属性,其规则是通过位运算"&"判断modifiers属性与对象属性的field.getModifiers()的值是否一致,来证明该属性是否被transient修饰过,如果是为真,表示剔除该属性,不进行序列化。

public boolean excludeField(Field field, boolean serialize) {
 // 通过if判断modifiers属性
 // private int modifiers = Modifier.TRANSIENT | Modifier.STATIC;
 if ((modifiers & field.getModifiers()) != 0) {
 return true;
 }
 ...
}

另外根据modifiers属性定义Modifier.TRANSIENT | Modifier.STATIC两种类型,一种是tranient,另一种是static静态类型。

Modifier.STATIC:静态类型
由约定三、我们知道,静态变量不会被序列化。

代码debug到此,我们已经知道Gson是如何判断对象的是否存在被transient修饰过属性以及如何过滤掉的呢。

总结

通过常用的Gson方式来验证tranient关键字,还可以通过java的io包下的 ObjectInputStream和ObjectOutputStream两个对象输入输出流也可以验证的,这里不做赘述,网上例子很多。

你可能感兴趣的:(Java经典语法:transient关键字使用总结)