Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/366.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java对象的深度克隆(不是bean)_Java_Performance_Copy_Deep Copy_Cloning - Fatal编程技术网

Java对象的深度克隆(不是bean)

Java对象的深度克隆(不是bean),java,performance,copy,deep-copy,cloning,Java,Performance,Copy,Deep Copy,Cloning,我目前正在处理的项目中有很多对象被序列化,以便获得现有对象的深度副本。在运行时有多个调用之前,这种方法可以很好地工作。在某些情况下,组件之间有100个、200个甚至1000个调用,而这正是性能问题困扰我们的地方 复制这些被克隆对象的历史原因是,在不同功能下处理相同对象的两个不同组件不应相互更改,例如,在按下“保存”或“同步”按钮之前,Swing UI中的更改不应更改后端中的对象值 我们有一个相当大的代码库,我想如果我写基于反射的克隆,它将比序列化工作得更快,但由于我们复杂的对象层次结构或其他原因

我目前正在处理的项目中有很多对象被序列化,以便获得现有对象的深度副本。在运行时有多个调用之前,这种方法可以很好地工作。在某些情况下,组件之间有100个、200个甚至1000个调用,而这正是性能问题困扰我们的地方

复制这些被克隆对象的历史原因是,在不同功能下处理相同对象的两个不同组件不应相互更改,例如,在按下“保存”或“同步”按钮之前,Swing UI中的更改不应更改后端中的对象值

我们有一个相当大的代码库,我想如果我写基于反射的克隆,它将比序列化工作得更快,但由于我们复杂的对象层次结构或其他原因,这种方法甚至更慢

我还尝试使用CloneUtils(sourceforge项目),这也比较慢(我们根本没有使用Hibernate)。SpringBeanutils不是一个选项(我从文档中假设它只使用bean,即内省,如果使用非标准访问器公开任何字段,我们将无法复制它们)


有没有人知道,在处理不同副本的同时提高性能。如果我们提供自己的复制方法,而不是序列化,我们有一个选项可以加快速度,但是,每次更新这些方法都有缺点,如果我们忘记了,我们可能会失去功能。

在这种情况下,给你一个如何提高性能的提示:如果你还没有使用模式,就使用它。你可能会获得一些性能。我怀疑你能做多少来提高性能重要的是,遵循您提到的方法。不幸的是,复制对象确实需要时间


稍微横向考虑一下,并且清楚地取决于您拥有的内存量以及读写器的比率(特别是如果每次写入都有多个读写器),创建副本缓存如何?

您可以通过动态类生成(例如使用)来避免反射。对于您使用的每个类,您将生成一个“cloner类”,其中包含复制所需的代码。如果所有字段至少都是包私有的,并且您将copier类放在同一个包中,那么这将使反射变得不必要。您需要一个默认的ctor,也不需要最终字段

在这里,序列化有一个优势,因为它使用
sun.misc.Unsafe
创建对象


在每个类中实现
deepClone
方法也可能是一种选择。它甚至可以与cloner类思想相结合。

您所描述的是一种管理可变状态的散弹枪方法。试图加快克隆速度只会给你带来有限的改进(比如一个数量级)。此外,如何克隆套接字、流或数据库连接

你真正需要的是用适当的命令/查询分离重构你的应用程序。这样,您将知道在哪里更改对象,在哪里不更改对象。如果不确定,可以使用单元测试来验证这一点


有许多技术可以帮助你-你可以改变你的一些对象是不可变的(这样你就可以自然地共享它们,在变异时创建新的副本);您可以使可变对象实现只读接口,并使用GUI中的RO视图等。

当您需要深度复制时,是否也需要深度复制所有关联?或者只是其中的一部分?手动实现
clone()
(我喜欢clone,不管我听说了什么),如果您需要性能提升,没有任何外部库能够显著击败java(反)序列化,因为它将依赖反射(在最佳情况下,它可能选择代码生成,但仍然…)实际上,prototype和编写复制方法没有什么不同。在我的例子中,有100个类需要编写克隆方法,因为我们需要深度复制。无论是编写clone还是copy方法,每次从这些类中添加或删除字段时,我们都必须更改copy/clone方法。如果使用
clone()
添加原语或不可修改的类(URL、字符串、数字、URI等),则无需更改。编写克隆方法可能需要一分钟。现在不考虑一个包含HASMAP的CalSS,它是另一个类型的对象(可能是基本类型,以便孩子也可以在那里),如果这些对象也包含了集合。你必须为每一个都编写克隆来深度克隆它们。并确保在每个类中复制集合的内容。Cloneable接口已损坏(有效的Java)。您需要2个实用程序函数来创建适当的映射/集合类型,然后遍历它们并调用clone()。如果您有循环引用,那么主要也是唯一的问题是正确地访问图形。还不到一分钟。老实说,我记不起写克隆()花了我这么多时间。啊,是的,而且忘了你需要一个额外的接口来使克隆()publicfield访问速度极快,带有反射(尤其是
setAccessible(true)
-完全删除安全检查)。您甚至可以使用Unsafe.getXXX进行绝对内联。再想一想,原语的装箱分配成本仍然需要支付。您可以对原语使用getType、getXXX和setXXX方法,但是,这仍然需要花费一些时间。您可以使用Unsafe.copymory获取浅层克隆,然后修复所有非基本字段。你需要知道这个物体的确切大小。是的,我承认这是一种鸟枪式的方法,但我们必须在时间特性上进行权衡。这个项目非常复杂,新功能在非常紧迫的期限内交付。是的,我承认这是一种猎枪式的方法,但我们必须在时间和功能之间进行权衡。这个项目是相当旧的和新的功能交付