序列化和反序列化

一.深拷贝和浅拷贝

1.深拷贝:

在拷贝引用类型成员变量时,为引用类型的数据成员开辟了一个独立的内存空间,实现真正内容上的拷贝,实现Serializable接口或者通过实现Cloneable接口实现(Serializable方式是通过java对象的序列化和反序列化的操作实现深拷贝.Cloneable接核心是Object类的native方法的clone())

1.1深拷贝特点:

(1) 对于基本数据类型的成员对象,因为基础数据类型是值传递的,所以是直接将属性值赋值给新的对象。基础类型的拷贝,其中一个对象修改该值,不会影响另外一个(和浅拷贝一样)。
(2) 对于引用类型,比如数组或者类对象,深拷贝会新建一个对象空间,然后拷贝里面的内容,所以它们指向了不同的内存空间。改变其中一个,不会对另外一个也产生影响。
(3) 对于有多层对象的,每个对象都需要实现 Cloneable 并重写 clone() 方法,进而实现了对象的串行层层拷贝。
(4) 深拷贝相比于浅拷贝速度较慢并且花销较大。

1.2结构图

在这里插入图片描述

2.浅拷贝:

只是增加了一个引用指向已存在的内存地址(需要实现Cloneable接口,并覆写clone()方法)

2.1.浅拷贝特点

(1) 对于基本数据类型的成员对象,因为基础数据类型是值传递的,所以是直接将属性值赋值给新的对象。基础类型的拷贝,其中一个对象修改该值,不会影响另外一个。
(2) 对于引用类型,比如数组或者类对象,因为引用类型是引用传递,所以浅拷贝只是把内存地址赋值给了成员变量,它们指向了同一内存空间。改变其中一个,会对另外一个也产生影响。

2.2结构图

在这里插入图片描述

2.3浅拷贝的实现
public class Student implements Cloneable{
    public Object clone(){
        try{
            //直接调用父类的clone()方法
            return super.clone();
        }catch(CloneNotSupportedException e){
            return null;
        }
    }
}

3.深拷贝和浅拷贝的区别

深拷贝和浅拷贝最根本的区别在于是否真正获取一个对象,假设B复制了A,修改A的时候,看是否B会发生变化

  • 如果B跟着也变了,说明是浅拷贝,拿人手短!(修改堆内存中的同一个值)
  • 如果B没有改变,说明是深拷贝,自食其力(修改堆内存中的不同的值)

4.注意

浅拷贝会带来数据安全方面的隐患,修改一个数据会影响到另一个数据的修改,因为他们都是指向同一个地址,所以这种情况下,需要用到深拷贝

二.序列化和反序列化

java序列化:把java对象转换为字节序列的过程
java反序列化:把字节序列恢复为java对象的过程

网络数据传输,双方需要约定好统一的数据格式(广泛使用的统一标准就是协议,小众就是序列化和反序列化)
一般把封装叫做序列化,解析或者分用叫做反序列化

在这里插入图片描述
浏览器封装细节:
在这里插入图片描述

1.实现序列化

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class JSONUtil {
    private static final ObjectMapper MAPPER = new ObjectMapper();
    /**
     * JSON 序列化:将java对象序列化为json字符串
     *
     * @param   o java对象
     * @return json 字符串
     */
    public static String serialize(Object o){

        try{
            return MAPPER.writeValueAsString(o);
        }catch(JsonProcessingException e){
            throw new RuntimeException("json序列化失败:"+o);
        }
    }
}

2.测试序列化操作


import org.junit.Assert;
import org.junit.Test;

import java.util.HashMap;
import java.util.Map;

public class JSONUtilTest {
    //单元测试:Junit框架使用方法上@Test注解,保证方法为public void
    @Test
    public void testSerialize(){
        //测试序列化操作:使用map模拟复杂
        Map map = new HashMap();
        map.put("className","java");
        map.put("students",new int[]{1,2});
        String json = JSONUtil.serialize(map);
        System.out.println(json);
        Assert.assertNotNull(json);
    }
}

运行结果
在这里插入图片描述

3.实现反序列化


import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;
import java.io.InputStream;

public class JSONUtil {
    private static final ObjectMapper MAPPER = new ObjectMapper();
    /**
     * 反序列化操作,将输入流/字符串反序列化为java对象
     * @param is 输入流
     * @param clazz  指定要反序列化的类型
     * @param <T>
     * @return 反序列化的对象
     */
    //InputStream输入流
    public static <T> T deserialize(InputStream is,Class<T> clazz){
        try {
            return MAPPER.readValue(is,clazz);
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("json反序列化失败:"+clazz.getName());
        }
    }
}

4.测试反序列化


import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

public class JSONUtilTest {
    //单元测试:Junit框架使用方法上@Test注解,保证方法为public void
    @Test
    public void testDeserialize(){
        //测试反序列化操作
        //类加载器加载某个资源,返回输入流
        InputStream is = JSONUtilTest.class.getClassLoader().
                getResourceAsStream("login.json");
        Map map = JSONUtil.deserialize(is,Map.class);
        System.out.println(map);
        Assert.assertNotNull(map);
    }
}

5.作用

  • 序列化最重要的作用:在传递和保存对象时.保证对象的完整性和可传递性。对象转换为有序字节流,以便在网络上传输或者保存在本地文件中。
  • 反序列化的最重要的作用:根据字节流中保存的对象状态及描述信息,通过反序列化重建对象。
  • 总结:核心作用就是对象状态的保存和重建。(整个过程核心点就是字节流中所保存的对象状态及描述信息)

6.序列化优点

  • 将对象转为字节流存储到硬盘上,当JVM停机的话,字节流还会在硬盘上默默等待,等待下一次JVM的启动,把序列化的对象,通过反序列化为原来的对象,并且序列化的二进制序列能够减少存储空间(永久性保存对象)。
  • 序列化成字节流形式的对象可以进行网络传输(二进制形式),方便了网络传输。
  • 通过序列化可以在进程间传递对象

7.序列化和反序列化的注意点

(1)序列化时,只对对象的状态进行保存,而不管对象的方法;

(2)当一个父类实现序列化,子类自动实现序列化,不需要显式实现Serializable接口;

(3)当一个对象的实例变量引用其他对象,序列化该对象时也把引用对象进行序列化;

(4)并非所有的对象都可以序列化,至于为什么不可以,有很多原因了,比如:

  • 安全方面的原因,比如一个对象拥有private,public等field,对于一个要传输的对象,比如写到文件,或者进行RMI传输等等,在序列化进行传输的过程中,这个对象的private等域是不受保护的;
  • 资源分配方面的原因,比如socket,thread类,如果可以序列化,进行传输或者保存,也无法对他们进行重新的资源分配,而且,也是没有必要这样实现;

(5)声明为static和transient类型的成员数据不能被序列化。因为static代表类的状态,transient代表对象的临时数据。
(6)序列化运行时使用一个称为 serialVersionUID 的版本号与每个可序列化类相关联,该序列号在反序列化过程中用于验证序列化对象的发送者和接收者是否为该对象加载了与序列化兼容的类。为它赋予明确的值。显式地定义serialVersionUID有两种用途:

  • 在某些场合,希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有相同的serialVersionUID;
    (7)Java有很多基础类已经实现了serializable接口,比如String,Vector等。但是也有一些没有实现serializable接口的;
    (8)如果一个对象的成员变量是一个对象,那么这个对象的数据成员也会被保存!这是能用序列化解决深拷贝的重要原因

三.代理服务器

代理服务器的功能是代理网络用户去取得网络信息,形象的说,它是网络信息的中转站,是个人网络和Internet服务商之间的中间代理机构,负责转发合法的网络信息,对转发进行控制和登记,代理服务器作为连接Internet与Intranet的桥梁,在实际应用中发挥着及其重要的作用,它可用于多个目的,最基本的功能是连接,此外还包括安全性,缓存,内容过滤,访问控制管理等功能,更重要的是,代理服务器是Internet链路级网管所提供的一种重要的安全功能,它的工作主要在开放系统互连(OSI)模型的对话层

1.正向代理服务器:抓包工具

位于客户端和原始服务器之间 的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并制定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端,客户端才能使用正向代理

1.1用途
  • 为在防火墙内的局域网客户端提供访问Internet的途径
  • 使用缓冲特性(由mod_cache提供)减少网络使用率
1.2区别

和反向代理不同之处在于,典型的正向代理是一种最终用户知道并主动使用的代理方式,例如Chrome浏览器中安装了switchysharp以后,通过switchysharp方便的进行代理转发服务,而为此用户必须要提前在switchysharp中做好配置才能达到相应的效果

2.反向代理服务器:nginx

位于用户与目标服务器之间,但是对于用户而言,反向代理服务器就相当于目标服务器,即用户直接访问反向代理服务器就可以获得目标服务器的资源,同时,用户不需要知道目标服务器的地址,也无须在用户端作任何设定,反向代理服务器通常可用来作为web加速,即使用反向代理作为web服务器的前置机来降低网络和服务器的负载,提高访问效率

2.1优点
  • 提高了内部服务器的安全
  • 加快了对内部服务器的访问速度
  • 节约了有限的IP资源
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值