如何正确使用Java序列化?

【入门篇】第五章 第一次与 AI Agent 交互 本文介绍了OpenClaw中最基本的用户与AI Agent交互方式,剖析了Agent和Gateway两个核心组件的作用,通过简单示例展示了从用户请求到结果返回的完整执行流程,说明了最小交互过程对验证系统可用性的重要意义,为后续学习复杂任务执行机制奠定基础。 阅读详情

前言

什么是序列化:将对象编码成一个字节流,这样一来就可以在通信中传递对象了。比如在一台虚拟机中被传递到另一台虚拟机中,或者字节流存储到磁盘上。

“关于Java的序列化,无非就是简单的实现Serializable接口”这样的说法只能说明停留在会用的阶段,而我们想要走的更远往往就需要了解更多的东西,比如:为什么要实现序列化?序列化对程序的安全性有啥影响?如何避免多余的序列化?…

本文主要参考资料《Effective Java》,其中代码除了只作部分说明,不能运行外,剩余代码都是亲自实践过的!

一、序列化代价

虽然实现Serializable很简单,但是为了序列化而付出的长期开销往往是实实在在的。实现Serializable接口而付出的最大代价是,一旦一个类被发布,就大大降低了“改变这个类的实现”的灵活性。

问:这个灵活性具体是指什么呢?

即一旦类实现了Serializable接口,并且这个类被广泛地使用,往往必须永远支持这种序列化形式,如果使用默认的序列化形式,那么这种序列化形式将永远地束缚在该类最初的内部表示法上,换句话说,一旦接受了默认的序列化形式,这个类中私有的和包级私有的实例域都变成导出的API的一部分,这显然是不符合的。这也就是实现序列化往往需要考虑到的几个代价,具体请往下看!

1、可能会导致InvalidClassException异常

如果没有显式声明序列版本UID,对对象的需求进行了改动,那么兼容性将会遭到破坏,在运行时导致InvalidClassException。比如:增加一个不是很重要的工具方法,自动产生的序列版本UID也会发生变化,则会出现序列版本UID不一致的情况。所以最好还是显式的增加序列版本号UID。

对User JavaBean实现Serializable接口,增加固定的序列版本号

public class User implements Serializable {
	/** 显示增加序列版本UUID,自动生成UUID可能会导致InvalidClassException */
	private static final long serialVersionUID = 1L;
	public User(int id, String name) {
		this.id = id;
		this.name = name;
	}
	private int id;
	private String name;
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	@Override
	    public String toString() {
		return "User{" +
		                "id=" + id +
		                ", name='" + name + ''' +
                '
	}
	';
    }
}

使用ObjectOutputStream与ObjectInputStream流控制序列与反序列

/**
 * @author jian
 * @date 2019/4/5
 * @description 测试序列化
 */
public class SeriablizableTest {
	public static void main(String[] args) {
		User user = new User(1, "lijian");
		serializeUser(user);
		deserializeUser();
	}
	/**
     * 使用writeObject方法序列化
     *
     * @param user
     */
	private static void serializeUser(User user) {
		ObjectOutputStream outputStream = null;
		try {
			// 创建对象输出流, 包装一个其它类型目标输出流,如文件流
			outputStream = new ObjectOutputStream(new FileOutputStream("D:\user.txt"));
			// 通过对象输出流的writeObject方法将对象user写入流中
			outputStream.writeObject(user);
			System.out.println("user序列化成功!");
		}
		catch (IOException e) {
			e.printStackTrace();
		}
		finally {
			if (outputStream != null) {
				try {
					outputStream.close();
				}
				catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
	private static void deserializeUser() {
		User user = null;
		Employee employee = null;
		ObjectInputStream inputStream = null;
		try {
			// 创建对象输出流, 包装一个其它类型目标输出流,如文件流
			inputStream = new ObjectInputStream(new FileInputStream("D:\user.txt"));
			// 通过对象输出流的writeObject方法将对象user写入流中
			user = (User)inputStream.readObject();
			System.out.println("user反序列化成功:" + user);
		}
		catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		catch (IOException e) {
			e.printStackTrace();
		}
		finally {
			if (inputStream != null) {
				try {
					inputStream.close();
				}
				catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
}

输出结果:先看user.txt文件中二进制文件流(因为txt打不开二进制流,所以是乱码)

之后再看控制台中,反序列化输出的User{id=1, name=‘lijian’},说明整个过程序列化成功!

之后去掉固定的序列版本号UID,让其自动生成,同时增加age属性(或者手动修改UID为2L)

private static final long serialVersionUID = 2L;

只进行反序列化将会报错:java.io.InvalidClassException

public static void main(String[] args) {
        User user = new User(1, "lijian");
//        serializeUser(user);
        deserializeUser();

    }

2、增加了出现Bug和安全漏洞的可能性

序列化机制是一种语言之外的对象创建机制,反序列化机制都是一个“隐藏的构造器”,具备与其他构造器相同的特点,正式因为反序列化中没有显式构造器,所以很容易就会忽略:不允许攻击者访问正在构造过程中的对象内部信息。换句话说,序列化后的字节流可以被截取进行伪造,之后利用readObject方法反序列会不符合要求甚至不安全的实例。

3、随着类发行新的版本,测试负担也会增加

一个可序列化的类被修订时,需要检查是否“在新版本中序列化一个实例,可以在旧版本中反序列化”,如果一个实现序列化的类有很多的子类或者是被修改时,就不得不加以测试。

二、序列化的缺陷

1、序列化是保存对象的状态,也就是不会关心static静态域,静态域不会被序列化。如User中count静态域。

public class User implements Serializable {
	private static final long serialVersionUID = 1L;
	private static int count = 1;
	public User(int id, String name) {
		// 约束条件name不能为null
		if (name == null || StringUtils.isEmpty(name)) {
			throw new NullPointerException("name is null");
		}
		this.id = id;
		this.name = name;
	}
	public User(){
	}
	;
	private int id;
	private String name;
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getCount() {
		return count;
	}
	public void setCount(int count) {
		User.count = count;
	}

赋值count为20:

public static void main(String[] args) {
        User user = new User();
        user.setName("Lijian");
        user.setId(1);
        user.setCount(20);
        serializeUser(user);
        deserializeUser();
}

序列化-反序列化

/**
     * 使用writeObject方法序列化
     *
     * @param user
     */
    private static void serializeUser(User user) {
        ObjectOutputStream outputStream = null;
        try {
            // 创建对象输出流, 包装一个其它类型目标输出流,如文件流
            outputStream = new ObjectOutputStream(new FileOutputStream("D:\\user.txt"));
            // 通过对象输出流的writeObject方法将对象user写入流中
            outputStream.writeObject(user);
            System.out.println("user序列化成功!");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private static void deserializeUser() {
        User user = null;
        ObjectInputStream inputStream = null;
        try {
            // 创建对象输出流, 包装一个其它类型目标输出流,如文件流
            inputStream = new ObjectInputStream(new FileInputStream("D:\\user.txt"));
            // 通过对象输出流的writeObject方法将对象user写入流中
            user = (User)inputStream.readObject();
            // User静态变量初始化为0,不会被反序列化
            System.out.println("user反序列化成功!");
            System.out.println("id:" + user.getId());
            System.out.println("name:" + user.getName());
            System.out.println("count:" + user.getCount());
        }  catch (ClassNotFoundException e) {
            e.printStackTrace();
        }  catch (IOException e) {
            e.printStackTrace();
        }
        finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

控制它输出:count明明被赋值为20,但是反序列化后输出为0,说明static是不会参数序列化的,跟transient类似。最终在反序列化过程中会被初始化为默认值(基本数据类型为0,对象引用为null,boolean为false)

2、在序列化对象时,如果该对象中有引用对象域名,那么也要要求该引用对象是可实例化的。如序列化User实例,其中引用了Employee实例,那么也需要对Employee进行可序列化操作,否则会报错: java.io.NotSerializableException

User增加对Employee引用:

 /** 对外引用其它对象,如果序列化该实例,则该对象实例也必须能实例化
(implement Serializable) */
    public Employee employee = new Employee(1, "Java programmer");

Employee不实现序列化:

public class Employee{
private int code;
    private String position;

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getPosition() {
        return position;
    }

    public void setPosition(String position) {
        this.position = position;
    }

    public Employee(int code, String position) {
        this.code = code;
        this.position = position;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "code=" + code +
                ", position='" + position + '\'' +
                '}';
    }
}

测试类:

/**
 * @author jian
 * @date 2019/4/5
 * @description 测试序列化
 */
public class SeriablizableTest {

    public static void main(String[] args) {
        User user = new User(1, "lijian");
        serializeUser(user);
        deserializeUser();

    }

    /**
     * 使用writeObject方法序列化
     *
     * @param user
     */
    private static void serializeUser(User user) {
        ObjectOutputStream outputStream = null;
        try {
            // 创建对象输出流, 包装一个其它类型目标输出流,如文件流
            outputStream = new ObjectOutputStream(new FileOutputStream("D:\\user.txt"));
            // 通过对象输出流的writeObject方法将对象user写入流中
            outputStream.writeObject(user);
            System.out.println("user序列化成功!");
        } catch (NotSerializableException e) {
            System.out.println("user引用employee对象域序列化失败");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private static void deserializeUser() {
        User user = null;
        Employee employee = null;
        int id = 0;
        ObjectInputStream inputStream = null;
        try {
            // 创建对象输出流, 包装一个其它类型目标输出流,如文件流
            inputStream = new ObjectInputStream(new FileInputStream("D:\\user.txt"));
            // 通过对象输出流的writeObject方法将对象user写入流中
            user = (User)inputStream.readObject();
            System.out.println("user引用employee对象域反序列化成功");
            System.out.println("user反序列化成功:" + user);
        } catch (WriteAbortedException e) {
            System.out.println("user引用employee对象域反序列化失败");
        }  catch (ClassNotFoundException e) {
            e.printStackTrace();
        }  catch (IOException e) {
            e.printStackTrace();
        }
        finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }
}

控制台输出结果:

要解决这样的问题,要么将 Employee implement Serializable ,要么对Employee对象实例transient修饰: public transient Employee employee = new Employee(1, “Java programmer”); 。但是需要注意的是序列化过程会对transient修饰的域初始化为默认值(对象引用为null,基本数据类型为0,boolean为false),所以执行以上代码会出现 java.lang.NullPointerException

3、默认序列化的过程可能消耗大量内存空间和时间,甚至可能会引起栈溢出:

因为第二条的原因,如果一个类中大量存在引用对象域,并且都需要实现序列化,那么整个序列化过程可能会很消耗时间,在通信传输过程中更是如此,同时序列化后的字节流需要足够大的内存。

三、提高序列化的安全性

1、编写readObject提供安全性与约束性

即使确定了默认的序列化形式是合适的,通常还必须提供一个readObject方法以保证约束关系和安全性。readObject方法相当于另一个共有构造器(可以认为是用“字节流作为唯一参数”的构造器),跟其它构造器一样,它也要求同样的所有主要事项:构造器必须检查参数的有效性,必要时对参数进行保护性拷贝等。readObject如果没有做到,那么对于攻击者来说违反这个类的约束条件相对就比较简单了,如果对一个人工仿造的字节流(人工修改从实例序列后的字节流)时,readObject产生的对象会违反所属类的约束条件。

1)为了解决这个问题,User中需要提供了readObject方法,该方法首先调用defalutReadObject,然后检查被反序列化之后的对象的有效性,如果有效性检查失败,readObject方法就会抛出InvalidObjectException异常,使反序列过程不能成功。

private void readObject(ObjectInputStream inputStream)
            throws IOException, ClassNotFoundException {
        inputStream.defaultReadObject();
}

User中的构造器中已对参数name约束为不能为null

public User(int id, String name) {
        // 约束条件name不能为null或空
        if (name == null || StringUtils.isEmpty(name)) {
            throw new NullPointerException("name is null or empty");
        }
        this.id = id;
        this.name = name;
}

2)那么readObject中也应该对其name进行约束,否则人工伪造的字节流很容易通过readObject构造出没有任何约束的对象实例,造成安全隐患。

private void readObject(ObjectInputStream inputStream)
            throws IOException, ClassNotFoundException {
        inputStream.defaultReadObject();

        // 约束条件name不能为null或空
        if (name == null || StringUtils.isEmpty(name)) {
            throw new NullPointerException("name is null or empty"); 
     }
}

尽管以上两种修正已经有效地避免攻击者创建无效的User实例,但是还有一种情况通过伪造字节流可以创建可变的User实例:比如User中增加Date对象引用birthday私有域,然后通过附加伪造字节流指向该birthday引用,攻击者从ObjectInputStream中读取User实例,然后读取附加后面的恶意Date引用,通过该Date引用就可以能够访问User对象内部私有Date域所引用的对象,从而改变User实例。


代码如下:

 public class MutableUser {

    public User user;
    public Date birthday;

    public MutableUser(){
        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream out = new ObjectOutputStream(bos);
            // 字节流有效的User实例开头,然后附加额外的引用
            out.writeObject(new User(new Date()));
            // 假设这是恶意的二进制,即附加恶意对象引用Date
            byte[] ref = {0x71, 0, 0x7e, 0 ,5};
            bos.write(ref);
            // 攻击者从ObjectInputStream中读取User实例,然后读取附加在后面的“恶意编制对象引用Date”
            ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
            user = (User) in.readObject();
            birthday = (Date) in.readObject();

        } catch (Exception e) {
      
        }
    }

    public static void main(String[] args) {
        MutableUser mutableUser = new MutableUser();
        User user = mutableUser.user;
        Date birthday = mutableUser.birthday;
        // 攻击者修改User内部birthday私有域,年份更改为2018
        birthday.setTime(2018);
        System.out.println(user);
    }
}

注:以上代码运行不了,只会加以解释说明而已,具体可以查看《Effective Java》中的代码举例

为了解决此问题,提出第三个安全措施

3)当一个对象被反序列化时,客户端不应该拥有对象的引用,如果哪个域包含了这样的对象引用,如果包含了私有的域(组件),就必须要保护性拷贝(非final域):当User对象在客户端MutableUser反序列化时,客户端拥有 了不该拥有的User私有域Date引用birthday,所以应该在readObject对birthday进行拷贝:

private void readObject(ObjectInputStream inputStream)
            throws IOException, ClassNotFoundException {
        inputStream.defaultReadObject();
        // 保护性拷贝birthday
        birthday = new Date(birthday.getTime());
        // 约束条件name不能为null
        if (name == null || StringUtils.isEmpty(name)) {
            throw new NullPointerException("name is null");
        }
    }

总结:

1)使用readObject其实就跟正常无参数的构造器一样,该满足的约束需要满足,同时必要时进行保护性拷贝。

2)反序列化过程最终会调用readObject方法,如下是一个异常栈的调用关系(代码中故意让readObject方法抛异常):deserialize---->ObjectInputStream.readObject----->ObjectInputStream.readObject0----->…User.readObject

2、使用readResolve增强单例

但是如果Sinleton类实现了序列化,那么它不再是一个Singleton,无论该类使用了默认的序列化形式,还是自定义的序列化形式,还是是否提供显式的readObject方法都没关系。任何一个readObject方法,不管是显式还是默认的,它都会返回一个新建的实例,这个新建的实例不同于该类初始化时创建的实例。
简单的Singleton:

public class Singleton {

    private static Singleton INSTANCE= new Singleton();
    private Singleton(){};
  .....
}

readResolve特性允许使用readObject创建实例代替另一个实例,如果一个类定义了readResolve方法,并且具备正确的声明,那么在反序列化的之后,新建的readResolve方法就会被调用,然后返回的对象引用将被返回,取代新建的对象。

public class Singleton implements Serializable {

    private static Singleton INSTANCE= new Singleton();
    private Singleton(){};
    
    private Object readResolve(){
        return INSTANCE;
    }
}
差分放大电路的计算 反馈,对于运算放大电路来说,运放工作在线性区,所以这里一定是负反馈,没有反馈(开环)或者是正反馈,那是比较器电路而不是放大电路,这时候运放工作在饱和区或称为非线性工作区,正因为饱和,输出才是电源电压的幅值。图2是一种带正反馈的运放电路,这里就不能叫运算放大电路了,因为运放的开环放大倍数理想是无限大,当然实际中不可能无限大,所以如下结构是迟滞电压比较器,运放工作在非线性区或饱和区。实际应用电路中,我们为了简化计算,也是用最简方法计算,经常使用的电路也是上述电路,令电阻相等关系,简化计算。 阅读详情

相关推荐

X猫免费小说安卓逆向分析

七猫免费小说安卓逆向分析 难度(♥♥) 文章目录七猫免费小说安卓逆向分析 难度(♥♥)1. 查壳2. 抓包分析3. sign1. Frida-rpc2. Native函数分析快3点了. 睡觉~ 白天再继续写! 1. 查壳 我这边使用的是ApkTool, 拖进去显示未加壳。 2. 抓包分析 POST https://xiaoshuo.wtzw.com/api/v1/login/index HTTP/1.1 net-env: 1 channel: qm-cbcpa056_wm is-white: 0 platf

Qiled的博客 4368

Java序列化的作用以及方法?

Java序列化的作用以及方法

西瓜的博客 747

Docker拉取ubuntu22.04镜像使用ROS2 humble及仿真工具可视化进行导航

Docker中安装Ubun22以及ROS,gazebo可视化等

lovebc的博客 1677

Java序列化的使用

准备一个枚举类,枚举类都继承了父类Enum,而Enum又实现了Serializable接口,所以enum类都可直接序列化 package serializable; public enum Gender { MALE,FEMALE } 准备被序列化的类 package serializable; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import

qq_40970962的博客 296

OpenHarmony 5.1 RK3568 开发板烧录:从源码编译到镜像写入的 6 步实战

本文详细解析了OpenHarmony 5.1在RK3568开发板上的全链路开发流程,包括环境搭建、源码编译、镜像烧录等6个关键步骤。通过实战指南和避坑技巧,帮助开发者快速掌握OpenHarmony系统的烧录与定制能力,提升物联网设备开发效率。

weixin_33722405的博客 343

告别Godot默认编辑器:手把手教你用VSCode配置C#开发环境(附中文注释避坑指南)

本文详细介绍了如何将VSCode配置为Godot引擎的C#开发环境,提升游戏开发效率。从环境准备、扩展配置到解决中文编码问题,提供完整的避坑指南和高级调试技巧,帮助开发者充分利用VSCode的智能补全和调试功能,打造高效工作流。

weixin_30596023的博客 189

​​Java 序列化入门:把对象变成 “文件” 的魔法

第1个问题: serialVersionUID序列化ID,可以看成是序列化和反序列化过程中的“暗号”,在反序列化时,JVM会把字节流中的序列号ID和被序列化类中的序列号ID做比对,只有两者一致,才能重新反序列化,否则就会报异常来终止反序列化的过程。如果在序列化某个类的对象时,就是不希望某个字段被序列化(比如这个字段存放的是隐私值,如:密码等),那这时就可以用transient修饰符来修饰该字段。:像 Redis 这类缓存工具,存对象时需要先序列化,取的时候再反序列化。接口的话,在序列化时会抛出。

qq_45438032的博客 837

C#实战大华智能安防系统:从SDK封装到视频流与智能报警的全链路落地

本文将介绍C#集成大华SDK开发安防系统的实战经验,重点解决多路视频预览卡顿和报警延迟问题。文章通过三层架构设计(SDK封装层、业务服务层、应用层)实现解耦,详细分析线程安全封装、高效解码显示和智能事件联动等核心技术。针对16路摄像头同时预览时CPU占用率过高的问题,提出使用子码流拉流与异步解码的优化方案,并总结8个常见开发陷阱的解决方案。文中还提供了大华智能安防系统的完整架构图,展示从设备层到应用层的交互流程,特别强调业务服务层中视频流服务和智能报警服务的核心功能设计。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 432

java之序列化与反序列化

序列化与反序列化的理解

m0_73866527的博客 1683

CAPL如何设置或修改CANoe TCP/IP协议栈的底层配置

MSS = MTU - tcpHeader - ipHeader,也就是MTU = MSS(1360) + tcpHeader(20) + ipHeader(20) = 1400,说明CAPL是可以动态设置网络底层配置参数的!然后在CAPL中设置此网卡MTU值为1400,然后创建UDP套接字,一次性发送2000个字节,在Trace窗口看看首帧报文二层Data的长度。所以我们还不能用UDP协议来验,应该用TCP协议来验,也就是在TCP三次握手时通过Tester的MSS值推导出自己的MTU值。

jasonj333 992

ESP32-C3模组上跑通HTTPS分次传输文件(1)

ESP32-C3模组上跑通HTTPS分次传输文件(1)

phmatthaus的专栏 760

java序列化怎么用

序列化是什么: 序列化就是将一个对象的状态(各个属性量)保存起来,然后在适当的时候再获得。 序列化分为两大部分:序列化和反序列化。序列化是这个过程的第一部分,将数据分解成字节流,以便存储在文件中或在网络上传输。反序列化就是打开字节流并重构对象。对象序列化不仅要将基本数据类型转换成字节表示,有时还要恢复数据。恢复数据要求有恢复数据的对象实例。 序列化有什么特点: 如果某个类能够被序列化,其子类也可以...

越来越好ing的博客 322

ANSYS WORKBENCH——参数化建模以及参数优化(结果导出为Excel)

目录 1、打开软件workbench 2、找到static structure,双击打开 3、选择材料 4、参数化建模 ​ 注:印记面的创建 5、模型属性设置 注:设置优化目标 6、回主界面,选择direct optimization模块 1、打开软件workbench 2、找到static structure,双击打开 3、选择材料 4、参数化建模 至此参数化建模就已经完成啦 注:印记面的创建 印记面一般是一个虚拟的区域,参与实际的网格划分,但是只是由于载.

python_AI_fans的博客 1万+

如何正确的使用Java序列化技术

1 Java 序列化技术概述Java 序列化技术可以使你将一个对象的状态写入一个Byte 流里,并且可以从其它地方把该Byte 流里的数据读出来。重新构造一个相同的对象。这种机制允许你将对象通过网络进行传播,并可以随时把对象持久化到数据库、文件等系统里。Java的序列化机制是RMI、EJB、JNNI等技术的技术基础。1.1 序列化技术基础并非所有的Java 类都可以序列化,为了使你指定的类可以

BlueDream的专栏 1480

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

如何正确的使用Java序列化技术(转)

如何正确的使用Java序列化技术(转) 摘要:本文比较全面的介绍了Java 序列化技术方方面面的知识,从序列化技术的基础谈起, 介绍了Java 序列化技术的机制和序列化技术的原理。并在随后的部分详细探讨了序列化的 高级主题-如何精确的控制序列化机制。通过阅读该文章,你可以了解如何使用Java 序列 化机制的方式和正确使用的方法,避免实际编程中对该技术的误用。并能掌握如何高效使

robin622的专栏 1965

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

如何正确的使用Java序列化技术(转贴)

摘要:本文比较全面的介绍了Java 序列化技术方方面面的知识,从序列化技术的基础谈起, 介绍了Java 序列化技术的机制和序列化技术的原理。并在随后的部分详细探讨了序列化的 高级主题-如何精确的控制序列化机制。通过阅读该文章,你可以了解如何使用Java 序列 化机制的方式和正确使用的方法,避免实际编程中对该技术的误用。并能掌握如何高效使用 该技术来完成特殊的功能。

小猫的窝棚 960

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

如何正确的使用Java序列化技术-

导读:   出自http://publishblog.blogchina.com/blog/tb.b?diaryID=279864   摘要:本文比较全面的介绍了Java 序列化技术方方面面的知识,从序列化技术的基础谈起,   介绍了Java 序列化技术的机制和序列化技术的原理。并在随后的部分详细探讨了序列化的   高级主题-如何精确的控制序列化机制。通过阅读该文章,你可以了解如何使用Ja

青潭狼的专栏 1507

java map 序列化json,java – 使用Jackson反序列化JSON Map并没有给出正确的Map

问题>首先,下面的序列化JSON序列化是否有意义?>如果是这样,为什么我没有收回地图?>在反序列化方面我能做些什么?Map< String,String>的JSON序列化财产(摘录):{"attributes": {"entry": [{"key": "operating system","value": "GNU/Linux"},{"key": "allergies...

weixin_33978451的博客 413

小鸟吹烟--如何正确的使用Java序列化技术-

导读:   出自http://publishblog.blogchina.com/blog/tb.b?diaryID=279864   摘要:本文比较全面的介绍了Java 序列化技术方方面面的知识,从序列化技术的基础谈起,   介绍了Java 序列化技术的机制和序列化技术的原理。并在随后的部分详细探讨了序列化的   高级主题-如何精确的控制序列化机制。通过阅读该文章,你可以了解如何使用Ja

青潭狼的专栏 1325

你不知道的java对象序列化的秘密

你知道序列化可以使用代理吗?你知道序列化的安全性吗?每个java程序员都听说过序列化,要存储对象需要序列化,要在网络上传输对象要序列化,看起来很简单的序列化其实里面还隐藏着很多小秘密,今天本文将会为大家一一揭秘。

程序那些事 1万+

枚举 反序列化 java_从JSON反序列化Java枚举

我们使用Jackson1.9.1对与Java对象之间的JSON请求响应字符串进行序列化和反序列化。原始Java类型,集合类型和自定义对象都可以(反)序列化而不会出现问题。但是,尝试将JSON字符串反序列化为Java枚举时遇到问题。JSON字符串的序列化方式如下:"wt":{"wt":100.5,"unit":{"LBS":3}}wt的Java类型如下所示:public class Weight {...

weixin_34255327的博客 1273
上一篇: Spring Boot 中实现定时任务的两种方式
下一篇: 设计模式-----Builder模式
Java_No2
博客等级 码龄7年 20粉丝 109原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值