<b>以下每一种方法都是一层拷贝(除开序列化反序列化的方式),都是将直接属性进行拷贝赋值</b>
1.实现bean的Cloneable接口
static class Body implements Cloneable{
public Head head;
public Body() {}
public Body(Head head) {this.head = head;}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
static class Head /*implements Cloneable*/{
public Face face;
public Head() {}
public Head(Face face){this.face = face;}
}
public static void main(String[] args) throws CloneNotSupportedException {
Body body = new Body(new Head());
Body body1 = (Body) body.clone();
System.out.println("body == body1 : " + (body == body1) );
System.out.println("body.head == body1.head : " + (body.head == body1.head));
}
- 只对bean的直接属性进行引用复制,如果直接属性是一个引用那么直接属性并没有实现拷贝,所以上述代码输出为
body == body1 : false
body.head == body1.head : true
- 只适用于同一种类型的class拷贝转换。
- 实现比较繁琐,需要拷贝的类都必须去实现clone方法,其他的方式只要有个一类就可以干事了。
- 效率非常非常高
json转换
以淘宝的fastjson库为例
static class Body {
public Head head;
public Body() {}
public Body(Head head) {this.head = head;}
}
static class Head {
public Face face;
public Head() {}
public Head(Face face){this.face = face;}
}
public static void main(String[] args) {
Body body = new Body(new Head());
Body body1 = JSONObject.parseObject(JSONObject.toJSONString(body), Body.class);
System.out.println("body == body1 : " + (body == body1) );
System.out.println("body.head == body1.head : " + (body.head == body1.head));
}
- 所有节点,所有层次全部实现深拷贝,以上代码输出为
body == body1 : false
body.head == body1.head : false
转换效率相比其他方式较差,不过fastjson号称fast,算法上做了很多优化,一般性能不十分敏感的应用都可以这样做,至少比apache的beanutil快。
不同class可以相互转换,转换前提是目标class的属性必须包含所有被复制对象的属性
对象全方位深拷贝的最简单实现方式。
类的默认构造器必须存在!!!!!!
BeanUtils工具类(org.springframework.beans.BeanUtils, org.apache.commons.beanutils.BeanUtils等)
static class Body {
public Head head;
public Body() {}
public Body(Head head) {this.head = head;}
}
static class Head {
public Face face;
public Head() {}
public Head(Face face){this.face = face;}
}
public static void main(String[] args) {
Body body = new Body(new Head());
Body body1 = new Body();
BeanUtils.copyProperties(body, body1);
System.out.println("body == body1 : " + (body == body1) );
System.out.println("body.head == body1.head : " + (body.head == body1.head));
}
- spring的beanutils其实就是包装了apache的beanutils而已
- 只对第一层属性进行复制,所以上述代码输出为:
body == body1 : false
body.head == body1.head : true
支持不同的实例间拷贝,不要求被复制对象和目标对象间属性列表必须是包含关系,两个对象属性完全不相同,该方法也不会报错
支持在参数后面添加,ignoreProperty可变参数
cglib库的BeanCopier
static class Body {
public Head head;
public Body() {}
public Body(Head head) {this.head = head;}
}
static class Head {
public Face face;
public Head() {}
public Head(Face face){this.face = face;}
}
public static void main(String[] args) {
Body body = new Body(new Head());
Body body1 = new Body();
BeanCopier bc = BeanCopier.create(Body.class, Body.class, false);
bc.copy(f, t, null);
System.out.println("body == body1 : " + (body == body1) );
System.out.println("body.head == body1.head : " + (body.head == body1.head));
}
- 其实现效果和beanutils一模一样,都是第一层复制,而且两个对象的属性有没有交集,需不需要全包含都没有要求
- beancopier支持自己是属性转换器对特殊的属性进行转换,如:
BeanCopier bc = BeanCopier.create(Body.class, Body.class, true); //这里要设置为true
bc.copy(f, t, new Converter(){
@Override
protected Object convert(Object value, Class target, Object context){
return null; //这里可以写自己的转换逻辑
}
});
还有其他的转换方式,暂时没有去探究
性能比较
以上代码分别执行500000次各自的运行时间
- cglib:239ms
- beanutils:2624ms
- json: 791ms
- jdk clone: 18ms
效率一目了然,然而各自有自己的优缺点和使用场景