构造器的陷阱
构造器是有返回值的,构造器返回它初始化的Java对象(用new调用构造器就可看到构造器的返回值)。也就是说,构造器的返回值类型总是当前类。
构造器不能声明返回值类型,也不能使用void声明构造器没有返回值。
当为构造器声明添加任何返回值类型声明,或者添加void声明该构造器没有返回值时,编译器并不会提示这个构造器有错误,只是系统会把这个所谓的构造器当成普通方法处理。
构造器并不会创建Java对象,构造器只是负责执行初始化,在构造器执行之前,Java对象所需要的内存空间,应该说是由new关键字申请出来的。绝大部分时候,程序使用new关键字为一个Java对象申请空间之后,都需要使用构造器为这个对象执行初始化。但在某些时候,程序创建Java对象无需调用构造器,以下两种方式创建的Java对性爱那个无需使用构造器:
使用反序列化的方式恢复Java对象;
使用clone方法复制Java对象。
反序列化方法:
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
classWolf implements java.io.Serializable{
private Stringname;
public Wolf(String name){
System.out.println("Constuctor");
this.name = name;
}
publicboolean equals(Object obj){
if(this == obj){
returntrue;
}
if(obj.getClass() == Wolf.class){
Wolf target = (Wolf)obj;
return target.name.equals(this.name);
}
returnfalse;
}
publicint hashCode(){
returnname.hashCode();
}
}
publicclass Serializable {
publicstaticvoid main(String[] args){
Wolf w = new Wolf("wolf");
Wolf w2 = null;
ObjectOutputStream oos = null;
ObjectInputStream ois = null;
try{
oos = new ObjectOutputStream(new FileOutputStream("a.bin"));
ois = new ObjectInputStream(new FileInputStream("a.bin"));
oos.writeObject(w);
oos.flush();w2 = (Wolf)ois.readObject();
System.out.println(w.equals(w2));
System.out.println(w == w2);
} catch (FileNotFoundException e) {
//TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
//TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}finally{
if(oos!=null){
try {
oos.close();
} catch (IOException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
}
if(ois!=null){
try {
ois.close();
} catch (IOException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
Output:
Constuctor
true
false
当创建Wolf对象时,程序调用了相应的构造器来对该对象执行初始化;当程序通过饭序列化机制恢复Java对象时,系统无需再调用构造器来执行初始化。
通过反序列化恢复出来的Wolf对象当然和原来的Wolf对象具有完全相同的实例变量值,但系统中将会产生两个Wolf对象。
如果想让序列化时也不会产生多个实例,应该这样写:
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamException;
classSingleton implements java.io.Serializable{
privatestatic Singletoninstance;
private Stringname;
private Singleton(String name){
System.out.println("Constructor");
this.name = name;
}
publicstatic Singleton getInstance(String name){
if(instance ==null){
instance =new Singleton(name);
}
returninstance;
}
private Object readResolve()throws ObjectStreamException
{
returninstance;
}
}
publicclass SingletonTest {
publicstaticvoid main(String[] args){
Singleton s = Singleton.getInstance("Wolf");
Singleton s2 = null;
ObjectOutputStream oos = null;
ObjectInputStream ois = null;
try{
oos = new ObjectOutputStream(new FileOutputStream("a.bin"));
ois = new ObjectInputStream(new FileInputStream("a.bin"));
oos.writeObject(s);
oos.flush();
s2 = (Singleton)ois.readObject();
System.out.println(s ==s2);
} catch (FileNotFoundException e) {
//TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
//TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}finally{
if(oos!=null){
try {
oos.close();
} catch (IOException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
}
if(ois!=null){
try {
ois.close();
} catch (IOException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
Output:
Constructor
True
当JVM反序列化地恢复一个新对象时,系统会自动调用这个readReslove()方法返回制定好的对象,从而保证系统通过反序列化机制不会产生多个Java对象。
除了可以反序列化机制恢复Java对象无需构造器之外,使用clone()方法复制Java对象也无需调用构造器。如果希望某个Java类的实例是可复制的,对该Java类有如下两个要求。
让该Java类实现Cloneable接口;
为该Java类提供clone()方法,该方法负责进行复制。
class Dog implements Cloneable{
private String name;
private double weight;
public Dog(String name,double weight){
System.out.println("Dog Class Constructor");
this.name = name;
this.weight = weight;
}
public Object clone(){
Dog dog = null;
try{
dog = (Dog)super.clone();
}catch(CloneNotSupportedException e){
e.printStackTrace();
}
return dog;
}
public boolean equals(Object obj){
if(this == obj){
return true;
}
if(obj.getClass() == Dog.class){
Dog target =(Dog)obj;
return target.name.equals(this.name) && target.weight == this.weight;
}
return false;
}
}
public class CloneTest {
public static void main(String[] args){
Dog dog = new Dog("Blot",9.8);
Dog dog2 = (Dog)dog.clone();
System.out.println(dog.equals(dog2));
System.out.println(dog==dog2);
}
}
output:
Dog Class Constructor
true
false