据我所知,基本上有两种方法可以在Java中创建全新的对象:1)使用new
运算符和2)通过序列化(例如,用于深度复制) 。所有其他对象操作(例如,分配)处理对现有对象的引用。但就内在逻辑而言,上述两种方式之间的区别是什么?似乎有一个区别是序列化不知何故不使用构造函数方法。我对吗?还有其他差异吗?
“内部逻辑”是指编译器(或处理它的人)如何逐步创建对象,它使用什么算法,使用什么方法等等。更像玛格丽特布鲁姆在她的回答中所写的内容,但更详细。
进一步混淆澄清:
因此,在反序列化期间,对象的副本是正确的:
class Class1 {
static ARRAY_LENGTH = 10;
public class1() {
int[] anArray = new int[ARRAY_LENGTH];
anArray[0] = 5;
...
anArray[9] = -2;
}
}
将包含一个创建了elsehow的数组的副本(如何?因为没有调用构造函数)?此外,虽然原始数组(序列化之前)是通过使用static
字段(在序列化过程中丢失)创建的,但其反序列化的副本将与原始数组完全相同?
答案 0 :(得分:3)
序列化和new
运算符完全不同,但它们都会导致对新分配的对象的引用。
您可以在{{3>}的 15.9.4类实例创建表达式的运行时评估章节中找到有关new
运算符的详细信息。
在运行时,类实例创建表达式的评估如下 [...]
接下来,为新的类实例分配空间。
[...] 新对象包含指定的所有字段的新实例 类类型及其所有超类 [...] 接下来,从左到右评估构造函数的实际参数。 [...]
接下来,调用指定类类型的选定构造函数。这会导致 为类类型的每个超类调用至少一个构造函数 类实例创建表达式的值是对新创建的引用 对象指定的类。每次评估表达式时,一个新对象 已创建。
编辑我的
长话短说,new
为新对象(特别是其字段的空间)分配空间,使用默认值初始化其字段并调用所选的构造函数。
Java Language Specification完全是另一回事。
存储和检索JavaTM对象的能力对于构建除瞬态应用程序之外的所有应用程序至关重要。 以序列化形式存储和检索对象的关键是表示足以重建对象的对象状态。 强调我的
这意味着序列化旨在允许程序员将对象状态保存到持久性介质中(在Java中抽象为 stream )和Java Serialization。
因此,deserializiation不会调用构造函数,因为通过从流中读取对象状态会自动恢复它。您可以覆盖默认行为。
从ObjectInputStream中读取对象类似于创建新对象。正如从超类到子类的顺序调用新对象的构造函数一样,从流中读取的对象从超类反序列化为子类。 在反序列化期间,为每个Serializable子类调用readObject或readObjectNoData方法而不是构造函数。
强调我的
说,我想强调一下,从概念的角度来看,使用new
和序列化是完全无关的事情。
在第一种情况下,您正在创建自己的新对象,在后者中,您正在读取以前保存的对象(可能由其他人)。
即使他们的最终结果被认为是相似的,但在你的脑海中,你应该在这两者之间有一个非常明确的区别。
答案 1 :(得分:0)
New运算符用于在内存中创建对象,而序列化是属于数据持久性的概念,它也可以用于在内存中创建新对象。
如果一个对象实现java.io.Serializable,它将被标记为Serializable Object,对象中的数据可以转换为字节流(serialize),我们可以使用这个字节流数据在内存中创建一个新对象(desrialize) 。 Java支持2个用于序列化和反序列化的对象,它们是ObjectInputStream和ObjectOutputStream
答案 2 :(得分:0)
不同意routine.workout = workout
:
实际上, Deserializiation 只是不调用类体中定义的构造函数。根据{{1}},它当然需要调用构造函数以从deserializiation does not invoke constructors
生成java.reflect
。它只是调用由 Object
创建的自定义构造函数。