哪个springboot 第三方jarr包可以实现对象的复制

博主最新文章
博主热门文章
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)------Java基础(77)
假如说你想复制一个简单变量。很简单:
int apples = 5;
int pears =
不仅仅是int类型,其它七种原始数据类型(boolean,char,byte,short,float,double.long)同样适用于该类情况。
但是如果你复制的是一个对象,情况就有些复杂了。
假设说我是一个beginner,我会这样写:
class Student {
private int
public int getNumber() {
public void setNumber(int number) {
this.number =
public class Test {
public static void main(String args[]) {
Student stu1 = new Student();
stu1.setNumber(12345);
Student stu2 = stu1;
System.out.println("学生1:" + stu1.getNumber());
System.out.println("学生2:" + stu2.getNumber());
学生1:12345
学生2:12345
这里我们自定义了一个学生类,该类只有一个number字段。
我们新建了一个学生实例,然后将该值赋值给stu2实例。(Student stu2 = stu1;)
再看看打印结果,作为一个新手,拍了拍胸腹,对象复制不过如此,
难道真的是这样吗?
我们试着改变stu2实例的number字段,再打印结果看看:
stu2.setNumber(54321)
System.out.println("学生1:" + stu1.getNumber())
System.out.println("学生2:" + stu2.getNumber())
学生1:54321
学生2:54321
这就怪了,为什么改变学生2的学号,学生1的学号也发生了变化呢?
原因出在(stu2 = stu1) 这一句。该语句的作用是将stu1的引用赋值给stu2,
这样,stu1和stu2指向内存堆中同一个对象。如图:
那么,怎样才能达到复制一个对象呢?
是否记得万类之王Object。它有11个方法,有两个protected的方法,其中一个为clone方法。
在Java中所有的类都是缺省的继承自Java语言包中的Object类的,查看它的源码,你可以把你的JDK目录下的src.zip复制到其他地方然后解压,里面就是所有的源码。发现里面有一个访问限定符为protected的方法clone():
Creates and returns a copy of this object. The precise meaning of "copy" may depend on the class of the object.
The general intent is that, for any object x, the expression:
1) x.clone() != x will be true
2) x.clone().getClass() == x.getClass() will be true, but these are not absolute requirements.
3) x.clone().equals(x) will be true, this is not an absolute requirement.
protected native Object clone() throws CloneNotSupportedE
仔细一看,它还是一个native方法,大家都知道native方法是非Java语言实现的代码,供Java程序调用的,因为Java程序是运行在JVM虚拟机上面的,要想访问到比较底层的与操作系统相关的就没办法了,只能由靠近操作系统的语言来实现。
1)第一次声明保证克隆对象将有单独的内存地址分配。
2)第二次声明表明,原始和克隆的对象应该具有相同的类类型,但它不是强制性的。
3)第三声明表明,原始和克隆的对象应该是平等的equals()方法使用,但它不是强制性的。
因为每个类直接或间接的父类都是Object,因此它们都含有clone()方法,但是因为该方法是protected,所以都不能在类外进行访问。
要想对一个对象进行复制,就需要对clone方法覆盖。
1、为什么要克隆
大家先思考一个问题,为什么需要克隆对象?直接new一个对象不行吗?
答案是:克隆的对象可能包含一些已经修改过的属性,而new出来的对象的属性都还是初始化时候的值,所以当需要一个新的对象来保存当前对象的“状态”就靠clone方法了。那么我把这个对象的临时属性一个一个的赋值给我新new的对象不也行嘛?可以是可以,但是一来麻烦不说,二来,大家通过上面的源码都发现了clone是一个native方法,就是快啊,在底层实现的。
提个醒,我们常见的Object a=new Object();Ob=a;这种形式的代码复制的是引用,即对象在内存中的地址,a和b对象仍然指向了同一个对象。
而通过clone方法赋值的对象跟原来的对象时同时独立存在的。
2、如何实现克隆
先介绍一下两种不同的克隆方法,浅克隆(ShallowClone)和深克隆(DeepClone)。
在Java语言中,数据类型分为值类型(基本数据类型)和引用类型,值类型包括int、double、byte、boolean、char等简单数据类型,引用类型包括类、接口、数组等复杂类型。浅克隆和深克隆的主要区别在于是否支持引用类型的成员变量的复制,下面将对两者进行详细介绍。
一般步骤是(浅克隆):
1) 被复制的类需要实现Clonenable接口(不实现的话在调用clone方法会抛出CloneNotSupportedException异常), 该接口为标记接口(不含任何方法)
2) 覆盖clone()方法,访问修饰符设为public。方法中调用super.clone()方法得到需要的复制对象。(native为本地方法)
下面对上面那个方法进行改造:
class Student implements Cloneable{
private int
public int getNumber() {
public void setNumber(int number) {
this.number =
public Object clone() {
Student stu = null;
stu = (Student)super.clone();
}catch(CloneNotSupportedException e) {
e.printStackTrace();
public class Test {
public static void main(String args[]) {
Student stu1 = new Student();
stu1.setNumber(12345);
Student stu2 = (Student)stu1.clone();
System.out.println("学生1:" + stu1.getNumber());
System.out.println("学生2:" + stu2.getNumber());
stu2.setNumber(54321);
System.out.println("学生1:" + stu1.getNumber());
System.out.println("学生2:" + stu2.getNumber());
学生1:12345
学生2:12345
学生1:12345
学生2:54321
如果你还不相信这两个对象不是同一个对象,那么你可以看看这一句:
System.out.println(stu1 == stu2);
上面的复制被称为浅克隆。
还有一种稍微复杂的深度复制:
我们在学生类里再加一个Address类。
class Address
public String getAdd() {
public void setAdd(String add) {
this.add =
class Student implements Cloneable{
private int
public Address getAddr() {
public void setAddr(Address addr) {
this.addr =
public int getNumber() {
public void setNumber(int number) {
this.number =
public Object clone() {
Student stu = null;
stu = (Student)super.clone();
}catch(CloneNotSupportedException e) {
e.printStackTrace();
public class Test {
public static void main(String args[]) {
Address addr = new Address();
addr.setAdd("杭州市");
Student stu1 = new Student();
stu1.setNumber(123);
stu1.setAddr(addr);
Student stu2 = (Student)stu1.clone();
System.out.println("学生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAdd());
System.out.println("学生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());
学生1:123,地址:杭州市
学生2:123,地址:杭州市
乍一看没什么问题,真的是这样吗?
我们在main方法中试着改变addr实例的地址。
addr.setAdd("西湖区")
System.out.println("学生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAdd())
System.out.println("学生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd())
学生1:123,地址:杭州市
学生2:123,地址:杭州市
学生1:123,地址:西湖区
学生2:123,地址:西湖区
这就奇怪了,怎么两个学生的地址都改变了?
原因是浅复制只是复制了addr变量的引用,并没有真正的开辟另一块空间,将值复制后再将引用返回给新对象。
所以,为了达到真正的复制对象,而不是纯粹引用复制。我们需要将Address类可复制化,并且修改clone方法,完整代码如下:
class Address implements Cloneable {
public String getAdd() {
public void setAdd(String add) {
this.add =
public Object clone() {
Address addr = null;
addr = (Address)super.clone();
}catch(CloneNotSupportedException e) {
e.printStackTrace();
class Student implements Cloneable{
private int
public Address getAddr() {
public void setAddr(Address addr) {
this.addr =
public int getNumber() {
public void setNumber(int number) {
this.number =
public Object clone() {
Student stu = null;
stu = (Student)super.clone();
}catch(CloneNotSupportedException e) {
e.printStackTrace();
stu.addr = (Address)addr.clone();
public class Test {
public static void main(String args[]) {
Address addr = new Address();
addr.setAdd("杭州市");
Student stu1 = new Student();
stu1.setNumber(123);
stu1.setAddr(addr);
Student stu2 = (Student)stu1.clone();
System.out.println("学生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAdd());
System.out.println("学生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());
addr.setAdd("西湖区");
System.out.println("学生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAdd());
System.out.println("学生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());
学生1:123,地址:杭州市
学生2:123,地址:杭州市
学生1:123,地址:西湖区
学生2:123,地址:杭州市
这样结果就符合我们的想法了。
最后我们可以看看API里其中一个实现了clone方法的类:
java.util.Date:
* Return a copy of this object.
public Object clone() {
Date d = null;
d = (Date)super.clone();
if (cdate != null) {
d.cdate = (BaseCalendar.Date) cdate.clone();
} catch (CloneNotSupportedException e) {}
该类其实也属于深度复制。
3、深克隆和浅克隆
在浅克隆中,如果原型对象的成员变量是值类型,将复制一份给克隆对象;如果原型对象的成员变量是引用类型,则将引用对象的地址复制一份给克隆对象,也就是说原型对象和克隆对象的成员变量指向相同的内存地址。
简单来说,在浅克隆中,当对象被复制时只复制它本身和其中包含的值类型的成员变量,而引用类型的成员对象并没有复制。
在Java语言中,通过覆盖Object类的clone()方法可以实现浅克隆。
在深克隆中,无论原型对象的成员变量是值类型还是引用类型,都将复制一份给克隆对象,深克隆将原型对象的所有引用对象也复制一份给克隆对象。
简单来说,在深克隆中,除了对象本身被复制外,对象所包含的所有成员变量也将复制。
在Java语言中,如果需要实现深克隆,可以通过覆盖Object类的clone()方法实现,也可以通过序列化(Serialization)等方式来实现。
(如果引用类型里面还包含很多引用类型,或者内层引用类型的类里面又包含引用类型,使用clone方法就会很麻烦。这时我们可以用序列化的方式来实现对象的深克隆。)
序列化就是将对象写到流的过程,写到流中的对象是原有对象的一个拷贝,而原对象仍然存在于内存中。通过序列化实现的拷贝不仅可以复制对象本身,而且可以复制其引用的成员对象,因此通过序列化将对象写到一个流中,再从流里将其读出来,可以实现深克隆。需要注意的是能够实现序列化的对象其类必须实现Serializable接口,否则无法实现序列化操作。
Java语言提供的Cloneable接口和Serializable接口的代码非常简单,它们都是空接口,这种空接口也称为标识接口,标识接口中没有任何方法的定义,其作用是告诉JRE这些接口的实现类是否具有某个功能,如是否支持克隆、是否支持序列化等。
4、解决多层克隆问题
如果引用类型里面还包含很多引用类型,或者内层引用类型的类里面又包含引用类型,使用clone方法就会很麻烦。这时我们可以用序列化的方式来实现对象的深克隆。
public class Outer implements Serializable{
private static final long serialVersionUID = 941L;
public Outer myclone() {
Outer outer = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(this);
      
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
outer = (Outer) ois.readObject();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
Inner也必须实现Serializable,否则无法序列化:
public class Inner implements Serializable{
private static final long serialVersionUID = L;
public String name = "";
public Inner(String name) {
this.name =
public String toString() {
return "Inner的name值为:" +
这样也能使两个对象在内存空间内完全独立存在,互不影响对方的值。
实现对象克隆有两种方式:
1). 实现Cloneable接口并重写Object类中的clone()方法;
2). 实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆。
注意:基于序列化和反序列化实现的克隆不仅仅是深度克隆,更重要的是通过泛型限定,可以检查出要克隆的对象是否支持序列化,这项检查是编译器完成的,不是在运行时抛出异常,这种是方案明显优于使用Object类的clone方法克隆对象。让问题在编译的时候暴露出来总是优于把问题留到运行时。
5、JAVA中JavaBean对象之间拷贝的方法
JAVA中JavaBean对象之间的拷贝通常是用get/set方法,但如果你有两个属性相同的JavaBean或有大部分属性相同的JavaBean,有个更简便的方法,他们之间的拷贝可以通过copyProperties方法进行。方法如下:
User u = new User()
u.setUid("1")
u.setName("tom")
u.setAge("18")
Student s = new Student()
BeanUtils.copyProperties(u, s)
System.out.println("[sid]"+s.getSid()+"#[name]"+s.getName()+"#[sex]"+s.getSex())
输出如下:
[sid]null#[name]tom#[sex]null
总结:copyProperties方法的作用是将两个对象之间相同的属性进行复制。比如上面两个JavaBean对象只有name属性相同,因此只成功复制了name属性的值
文章:11篇
阅读:17951
文章:23篇
阅读:32588
文章:22篇
阅读:447001,697被浏览62,864分享邀请回答commons.apache.org/。apache commons 涵盖了大量的小工具,比如发邮件(线上告警用),快速且方便的IO操作封装。等等工具很多,可以自己慢慢去学习。4.netty 一个网络通信框架,当需要实现自定义协议的时候我就用这个,netty的新版本自带了很多协议的实现版本,这是搞网络快速开发不二的选择。5.httpclient 系列主要是用在测试线上服务的时候用的。毕竟是一个基于http协议网络工具,当开发的web上线的时候,利用httpclient来写测试用例,效果很不错。测试的工具有很多,但是这个可以满足你定制http请求的需求。服务类:1.jettyhttpclient 的同一个项目下有一个简易的http server 但是没有实现servlet,这个时候jetty的效果就体现出来了。特别的是,当你打算对 jsp jstl 等方式编写的网页进行功能测试的时候,jetty就可以承担 mock的作用,好用得很。使得你可以在junit的框架下对jsp编写的网页进行测试。2.maven现在的java已经离不开这个玩意了。你可以自己搭建一个nexus 来做maven私服。当你存在RPC的需求的时候。完全可以把自己的接口部分和client打包上传到maven私服,调用的服务只需要include这个包就可以远程调用你的服务了。在国内配合上dubbo这类 SOA框架。那个效果酸爽的很。完成了实际意义上的接口于实现在网络层级的分离。让java 的package 形成一个网络上的package。需要某个服务的时候,include 直接调用。其他的一律不用管。 先那么多,后续再补=======================补充分割线1. Disruptor
高性能的并发框架,一般用来在涉及到 生产者--消费者模型的时候会用到。抛开性能不谈(实际上性能相当棒)它的抽象方式和接口都设计得很好。2.quartz 一个调度器,当涉及到多任务定时调用的时候这个框架能帮上非常多。特别在网络游戏服务器中,如果需要定时或者短时定时来做某些事情的时候(用户的长时间buff状态,刷新时间等),quart是一个非常不错的选择。如果时间比较短的话,利用java内置的DelayQueue 也可以。30821 条评论分享收藏感谢收起create.select(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME, count())
.from(AUTHOR)
.join(BOOK).on(AUTHOR.ID.equal(BOOK.AUTHOR_ID))
.where(BOOK.LANGUAGE.eq("DE"))
.and(BOOK.PUBLISHED.gt(date("")))
.groupBy(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)
.having(count().gt(5))
.orderBy(AUTHOR.LAST_NAME.asc().nullsFirst())
.offset(1)
SELECT AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME, COUNT(*)
FROM AUTHOR
JOIN BOOK ON AUTHOR.ID = BOOK.AUTHOR_ID
WHERE BOOK.LANGUAGE = 'DE'
AND BOOK.PUBLISHED & DATE ''
GROUP BY AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME
HAVING COUNT(*) & 5
ORDER BY AUTHOR.LAST_NAME ASC NULLS FIRST
既可以做orm,也可以只作为sql构造器使用,执行交由其他组件完成--------------------------------------------------------------------------------不要和另一个spark搞混了,这是一个极简的web框架,来源于ruby的Sinatra。使用它只需要几行代码就可以创建好一个接口,采用内置jetty即可运行,同时也支持模板渲染,用来快速开发一些小项目很合适。同样是官网的例子,感受一下,有没有一种在写nodejs的感觉import static spark.Spark.*;
public class HelloWorld {
public static void main(String[] args) {
get("/hello", (req, res) -& "Hello World");
303 条评论分享收藏感谢收起8608人阅读
_____1.1.5 java杂识(10)
1.为什么要使用BeanUtils组件?
由于我们经常操作javabean,很频繁的get和set来实现属性的复制,apache提供了这个BeanUtils来实现直接对象的拷贝。
2.BeanUtils的基本实现
下面两个包是必须要导入的,第一个是源码包。
实现对象的复制:
public class User {
public Integer getId() {
public void setId(Integer id) {
public String getUsername() {
public void setUsername(String username) {
this.username =
public String getGender() {
public void setGender(String gender) {
this.gender =
public void test1() throws Exception{
User user=new User();
BeanUtils.copyProperty(user, "id", "1");
BeanUtils.copyProperty(user, "gender", "男");
System.out.println("单个属性值传入的方式:"+user.getId()+", "+user.getGender());
User newUser=new User();
BeanUtils.copyProperties(newUser, user);
System.out.println("整个对象拷贝:"+newUser.getId()+", "+newUser.getGender());
Map&String,Object& map=new HashMap&String,Object&();
map.put("username", "Jerry");
BeanUtils.populate(newUser, map);
System.out.println("拷贝map对象:"+newUser.getUsername());
单个属性值传入的方式:1, 男
整个对象拷贝:1, 男
拷贝map对象:Jerry
3.日期转换器工具
public class User {
public Integer getId() {
public void setId(Integer id) {
public String getUsername() {
public void setUsername(String username) {
this.username =
public String getGender() {
public void setGender(String gender) {
this.gender =
public Date getBirth() {
public void setBirth(Date birth) {
this.birth =
增加了生日属性,是日期类型的。
如果我们直接使用BeanUtils.copyProperty(user,"birth",birthString);那么就会报以下警告,转换也不成功。BeanUtils不会把String类型自动转成Date类型。
日期转换器工具类实现:
public void test2() throws Exception{
User newUser=new User();
String birthString="";
ConvertUtils.register(new Converter(){
public Object convert(Class type, Object value) {
if( type != Date.class)
if(value == null || "".equals(value.toString().trim()))
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
return sdf.parse(value.toString());
} catch (ParseException e) {
throw new RuntimeException(e);
},Date.class);
BeanUtils.copyProperty(newUser, "birth", birthString);
System.out.println(newUser.getBirth());
Thu Sep 30 00:00:00 CST 1993
通过ConvertUtils的register方法内自定义一个转换器来实现String类型的日期转为Date类型的日期。
使用组件提供的日期转换工具类:
public void test3() throws Exception{
User newUser=new User();
String birthString="";
ConvertUtils.register(new DateLocaleConverter(), Date.class);
BeanUtils.copyProperty(newUser, "birth", birthString);
System.out.println(newUser.getBirth());
Mon Oct 17 00:00:00 CST 2016
文章:21篇
阅读:6048
文章:24篇
阅读:7909博主最新文章
博主热门文章
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)}

我要回帖

更多关于 springboot 第三方jar 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信