反序列化,反射时,构造函数是否调用。

目录

■反射,反序列化时,构造函数是否调用

反序列化时,不被调用

反射时,被调用

■验证代码---反序列化

Person

Test

运行结果

■验证代码---反射

Person(反射)

Test(反射)

运行结果(反射)

■扩展

JDBC连结中Class.forName()


■反射,反序列化时,构造函数是否调用

反序列化时,不被调用

当反序列化对象时,不会调用类的构造方法。相反,Java 反序列化机制会使用一些特殊的机制将数据转换为对象,而不需要调用构造方法。这可以通过读取对象序列化数据流并进行对象重建来实现。在这个过程中,对象的构造方法并不会被调用,而是通过使用类的特殊方法来重新构建对象实例。

===

为什么反序列化时,构造方法不被调用

当通过反序列化生成对象时,构造函数不被调用的原因是因为反序列化是通过读取对象的字节流来恢复对象的状态,而不是通过调用对象的构造函数来创建对象。在反序列化过程中,对象的状态是从字节流中读取并设置的,因此不会调用构造函数。

反序列化通常会使用特定的反序列化方法来恢复对象的状态,这些方法会在对象创建后被调用。因此,在反序列化过程中,构造函数不会被调用。

需要注意的是,在进行反序列化时,如果需要执行特定的初始化操作,可以使用readObject方法来自定义对象的反序列化行为,根据需要在readObject方法中执行初始化操作。

===

反射时,被调用

当使用反射创建类的实例时,构造方法确实会被调用。通过反射创建实例时,需要首先获取类的构造方法,然后使用构造方法的newInstance()方法来创建实例。这样就会触发相应构造方法的调用。

==

■验证代码---反序列化

Person

package com.sxz.study.objectStream;

import java.io.Serializable;

public class Person implements Serializable {

    /**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	/**
     * 姓名
     */
    private String name;
    /**
     * 年龄
     */
    private Integer age;

    public Person() {
    }

    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
        System.out.println("构造函数调用!!!");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

Test

package com.sxz.study.objectStream;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class Test {

	public static void main(String[] args) {

		// 实例化一个 Person 对象
		Person person = new Person("Zhang San", 28);

		// 通过 FileOutputStream 创建一个 ObjectOutputStream 实例
		ObjectOutputStream oos;
		try {
			oos = new ObjectOutputStream(new FileOutputStream("C:\\test\\objectStream\\person001.txt"));
			// 将 Person 对象写入流中
			oos.writeObject(person);
			// 关闭流并释放资源
			oos.close();
			
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		// 通过 FileInputStream 实例来创建一个 ObjectInputStream 实例
		ObjectInputStream ois;
		try {
			ois = new ObjectInputStream(new FileInputStream("C:\\test\\objectStream\\person001.txt"));
			// 读取对象 【!!!不会调用构造方法!!!】
			Object o = ois.readObject();
			// 关闭流并释放资源
			ois.close();
			// 打印对象
			System.out.println(o.toString());
		} catch (IOException | ClassNotFoundException e) {
			e.printStackTrace();
		}

	}

}

运行结果

构造函数调用!!!
Person{name='Zhang San', age=28}

====

■验证代码---反射

Person(反射)

package com.sxz.study.objectReflect;

public class Person {
    public Person() {
        System.out.println("Person的无参构造方法被调用");
    }
}

Test(反射)

package com.sxz.study.objectReflect;

import java.lang.reflect.Constructor;

public class Test {

	public static void main(String[] args) {
	    try {
	        Class personClass = Class.forName("com.sxz.study.objectReflect.Person");
	        Constructor constructor = personClass.getConstructor();
	        Object person = constructor.newInstance();
	    } catch (Exception e) {
	        e.printStackTrace();
	    }
	}

}

运行结果(反射)

Person的无参构造方法被调用

// Object person = constructor.newInstance();  执行完这一句之后,构造方法才被调用!

==

■扩展

JDBC连结中Class.forName()

・java开发中,采用JDBC连接数据库,最经常用到的就是Class.forName()这个方法.

・Class.forName(String className)在JDK帮助文档中是这样说的:返回与带有给定字符串名的类或接口相关联的Class对象,

・参数className是所需类的完全限定名;返回值是具有指定名的类的Class对象.如调用Class.forName("x") 将导致名为x的类被初始化.

Class.forName("com.mysql.jdbc.Driver");      
String url = "jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf-8";      
String user = "test";      
String psw = "test";      
Connection con = DriverManager.getConnection(url,user,psw);    

===

你可能感兴趣的:(java,python,开发语言)