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

目录

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

反序列化时,不被调用

反射时,被调用

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

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);    

===

  • 8
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
序列化和反序列化可以破坏单例设计模式的安全性。当一个单例类被序列化后,然后再进行反序列化创建出一个新的实例,从而破坏了单例的特性。这是因为序列化和反序列化过程中创建一个新的对象,并不调用类的构造函数来初始化新对象。因此,即使单例类被序列化和反序列化,也不能保证只有一个实例存在。 为了解决这个问题,可以在单例类中添加一个readResolve方法,并在该方法中返回单例实例。这样,在反序列化,就可以通过readResolve方法返回已存在的单例实例,而不是创建一个新的实例。通过这种方式,可以确保单例模式的安全性,避免了序列化和反序列化破坏单例的问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [深入浅出单例模式与反射与序列化对单例的破坏](https://blog.csdn.net/weixin_43975523/article/details/103140654)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [设计模式|序列化、反序列化对单例的破坏、原因分析、解决方案及解析](https://blog.csdn.net/leo187/article/details/104332138)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值