import java.io.*;
class Animal implements Serializable
{
String type;
Animal()
{
System.out.println("Animal's default constructor");
}
}
class Dog extends Animal
{
int weight;
Dog(String type, int weight)
{
this.type = type;
this.weight = weight;
System.out.println("running the Dog's dual arg'd constructor");
}
}
class DogSerialized
{
public static void main(String[] args)
{
Dog d = new Dog("hairy",29);
System.out.println(d.type+" "+d.weight);
try{
FileOutputStream fs = new FileOutputStream("fileSerialized.ser");
ObjectOutputStream os = new ObjectOutputStream(fs);
os.writeObject(d);
os.close();
}//end of try block
catch(Exception e){}
Dog d1 = null;
try{
FileInputStream fis = new FileInputStream("fileSerialized.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
d1 = (Dog) ois.readObject();
}//end of try block
catch(Exception e){}
System.out.println(d1.type+" "+d1.weight);
}
}
运行此代码,我能够看到调用super的构造函数。我不知道为什么/如何调用它。你能否解释一下这种特殊情况(序列化 - 反序列化超级为Serializable的子类实例)
答案 0 :(得分:1)
它的代码Dog d = new Dog("hairy",29);
调用超类构造函数而不是序列化过程。每当您创建子类的对象时,它都会调用其父类的构造函数。
答案 1 :(得分:1)
您的问题与序列化无关。使用new
创建任何实例时,构造函数将运行。当对象被反序列化时,它们不会运行。
一个超类的构造函数是隐式调用的,因为编译器会为你插入一个对super();
的无参数调用,作为子类构造函数中的第一个语句。要更清楚地理解这个概念,您必须了解构造函数链接。它只不过是在Java中,每个构造函数都会调用构造函数
它的超类隐式调用super();
,除非你明确调用this();
(请参阅重载的construtors)。
在您的情况下,Dog extends Animal
和Animal extends Object
(因为我们在Java中创建的每个类都将扩展Object
类。)
现在,当您在main方法中说Dog d = new Dog("hairy",29);
时,会执行以下步骤
Dog
构造函数。但它不会初始化
您的变量type
和weight
。由于您Dog的构造函数中的第一个语句是super();
(隐式),调用你的Animal
类的构造函数。
您的Animal的构造函数中的第一个语句是super();
(隐式)所以Object
类的构造函数被调用。
此时我们处于堆栈顶部,因为Java中的类Object
在继承层次结构中处于最高级别。所以对象
构造函数完成并弹出堆栈。
Animal
。它将完成
super()之后的语句;声明和弹出的
叠加。Dog
。它也将完成所有
其中的剩余语句并弹出堆栈。来到您的示例,当您致电Dog d = new Dog("hairy",29);
时,编译器会插入super();
,如下所示
Dog(String type, int weight)
{
super(); //You can also explicitly state this. This will invoke Animal() constructor before going to below statements.
this.type = type;
this.weight = weight;
System.out.println("running the Dog's dual arg'd constructor");
}
要点:
super();
或明确调用this();
当您明确调用super();
时,其中的参数应匹配
使用超类构造函数的参数。例如,如果您的Animal构造函数有2个参数,例如Animal(String type, int weight)
,并且在Dog构造函数中调用super();
,则会出现编译器错误。
构造函数永远不会被继承。它们无法被覆盖。
答案 2 :(得分:0)
构造函数不在子类中继承。因此,为了创建子类对象,首先需要通过调用超级构造函数来创建基类(超类)对象(在您的示例中非常正常)。在创建super之后,调用子类构造函数以添加任何子类字段。对象就像阴离子:内层是超类,外层是子类。
您可以在此article中详细了解它。
答案 3 :(得分:-1)
接口,Serializable与否,对调用构造函数没有任何影响。
子类在创建父类时始终调用它的父元素的构造函数。
您可以尝试将Animal类更改为:
class Animal implements Serializable
{
String type;
Animal(String something)
{
System.out.println("Animal's default constructor");
}
}
代码将无法编译,因为在Dog构造函数中,您不会调用其父代的构造函数。