Java 직렬화 직렬화 가능

高洛峰
풀어 주다: 2017-03-18 11:35:49
원래의
3078명이 탐색했습니다.

Java 직렬화 직렬화 가능

Java의 직렬화 과정은 다음과 같습니다.

Java 직렬화 직렬화 가능

Java의 직렬화 해제 과정은 다음과 같습니다.

Java 직렬화 직렬화 가능

참고: 모든 클래스를 직렬화할 필요는 없습니다.

1) 보안 문제는 두 가지 주요 이유가 있습니다. Java의 일부 클래스는 민감한 클래스이며 이러한 유형의 객체 데이터는 외부 세계에 공개되기가 불편합니다. 직렬화된 객체 데이터는 쉽게 해독될 수 있으므로 일반적으로 이러한 유형의 객체는 보안을 보장할 수 없습니다. 객체는 직렬화되지 않습니다.

2) 자원 문제. 직렬화된 바이트 스트림을 사용하여 객체를 생성할 수 있으며 이 생성에는 제한이 없습니다. 때로는 객체를 너무 많이 생성하면 큰 리소스 문제가 발생할 수 있으므로 이러한 객체는 직렬화에 적합하지 않습니다.

직렬화 가능

직렬화 가능은 Java에서 제공하는 직렬화 인터페이스로 객체에 대한 표준 직렬화 및 역직렬화 작업을 제공하는 빈 인터페이스입니다.

직렬화 과정:

Person p = new Person("name","id");
        File file = new File("cache.txt");
        FileOutputStream output = new FileOutputStream(file);
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(output);
        objectOutputStream.writeObject(p);
        output.close();
        objectOutputStream.close();
로그인 후 복사

직렬화 과정:

File file = new File("cache.txt");
        FileInputStream input= new FileInputStream(file);
        ObjectInputStream objectInputStream = new ObjectInputStream(input);
        Person p = (Person)objectInputStream.readObject();
        System.out.println(p.getName()+"---"+p.getId());
        input.close();
        objectInputStream.close();
로그인 후 복사

직렬화해야 하는 클래스 멤버

언제 객체를 직렬화할 때 모든 멤버를 이진 바이트 시퀀스로 변환할 필요는 없습니다. 왜냐하면 저장 공간이나 전송 공간을 절약하고 직렬화 효율성을 높이기 위해 일부 불필요한 멤버를 직렬화할 필요가 없기 때문입니다. 여기에는 다음이 포함됩니다.

정적 변수. 정적 변수는 클래스의 특성에 속하고 특정 인스턴스에 속하지 않으므로 직렬화 중에 직렬화할 필요가 없으며 역직렬화 중에 클래스의 정적 멤버 참조를 직접 얻을 수 있습니다.

방법. 메서드는 단지 작업 집합일 뿐입니다. 메서드는 개체에 의존하지 않으며 개체에 따라 작업이 다르지 않습니다. 역직렬화 중에 메서드 정보를 클래스에서 직접 얻을 수도 있습니다.

상속 관계 직렬화

상위 클래스가 Serialized를 구현하면 하위 클래스도 직렬화되고 상위 클래스도 직렬화됩니다. 직렬화 가능을 구현하는 클래스를 직렬화하면 해당 참조 클래스도 직렬화됩니다. 참조 클래스가 Serialize 인터페이스를 구현하지 않으면 JVM은 java.io.NotSerializedExeception을 발생시킵니다.

이때 Person 클래스가 직렬화되면 Tool 클래스도 동시에 직렬화됩니다. 시간. Tool 클래스가 직렬화 가능 인터페이스를 구현하지 않으면 예외가 발생합니다.

민감한 데이터 보호:

직렬화 식별자를 사용하여 클래스를 추가한 후 클래스 객체의 모든 속성 정보가 직렬화되어 로컬에 저장되거나 네트워크. 그런 다음 개체의 일부 필드가 민감한 정보이므로 노출되어서는 안 되는 경우가 있습니다. 직렬화되어 있으면 쉽게 크랙될 수 있어 공통 비밀번호 필드 등 보안 위험이 발생할 수 있습니다.
class Person implements Serializable{
    private String name;
    private Tool tool = new Tool();
}

class Tool implements Serializable{
    
}
로그인 후 복사

Java는 임시 키워드인 임시 키워드를 제공합니다. 이 키워드는 보호된 정보가 직렬화를 통해 노출되지 않도록 필드 직렬화를 해제합니다.

직렬화 ID

이 시나리오를 상상해 보세요. 양쪽 끝이 직렬화된 개체를 네트워크를 통해 전송하고 있는데 어떤 이유로 양쪽 끝에서 사용하는 클래스 버전이 변경되었습니다. 다르게, 수신자의 클래스에 여러 필드가 제거되었다고 가정합니다. 송신자가 객체의 직렬화된 바이트 스트림을 수신자에게 보낼 때 수신자의 클래스에 여러 필드가 누락되어 구문 분석할 수 없습니다.

Java에서는 직렬화 인터페이스를 구현하는 클래스가 serialVersionUID 정적 속성을 선언해야 한다고 요구합니다. 이러한 속성이 없으면 JVM은 자동으로 속성을 선언하고 속성에 값을 할당합니다. 수업이 바뀔 때 배정됨) ). 이 속성의 값은 고유하며 다양한 직렬화 클래스를 식별하는 데 사용됩니다. 클래스의 직렬화 식별자가 정확히 동일한 경우에만 Java는 역직렬화 작업을 수행합니다. 이것이 직렬화 식별자의 역할입니다.

위에서 언급한 시나리오의 경우 serialVersionUID를 수동으로 선언하지 않는다고 가정하면 JVM은 송신자와 수신자가 사용하는 클래스에서 serialVersionUID에 서로 다른 값을 할당하므로 deserialization이 실패합니다. serialVersionUID를 수동으로 할당하면 클래스의 필드가 변경되더라도 역직렬화에 성공할 수 있습니다.

사용자 정의 직렬화 전략

사용자 정의 직렬화 전략

Java는 직렬화 및 역직렬화를 허용하는 효과적인 메커니즘을 제공합니다. 이때 해당 처리에 대해 사용자 정의 방법을 사용합니다. 전송 당사자가 직렬화 전략에 동의한 후에는 이 전략 세트를 구현하기 위해 전송해야 하는 일련의 메소드를 직렬화 클래스에 추가하기만 하면 직렬화 및 역직렬화를 위해 지정된 메소드가 자동으로 호출됩니다. 방법은 다음과 같습니다.

1) private void writeObject(ObjectOutputSteam out)가 IOException을 발생시킵니다 

  在方法的内部有重要的代码:out.defaultWriteObject()   //将对象数据以默认方式写入到输出流中

    2)private void readObject(ObjectInputStream in) throws IOException,ClassNotFoundException

  同样的,此方法内部也有相似代码:in.defaultReadObject();  //以默认方式从输入流中恢复对象

这两个方法的作用分别是将特定的对象写入到输出流中以及从输入流中恢复特定的对象,通过这两个方法,用户即可实现自定义的序列化。当在实现Serializable接口的类中写了上面两个方法之后,序列化或反序列化该类时则会通过反射来调用这两个方法,从而实现自定义序列化。

限制序列化对象的数量

我们看下面的单例模式:

public class Singleton implements Serializable {

    private volatile static Singleton mInstance;
    private Singleton() {
    }

    public static Singleton getInstance() {
        if (mInstance == null) {
            synchronized (Singleton.class) {
                if (mInstance == null) {
                    mInstance = new Singleton();
                }
            }
        }
        return mInstance;
    }
}
로그인 후 복사

此时通过反序列化获取实例,则单例模式会失效。那该如何解决这个问题呢?

  Java有一种机制,可以让我们在序列化和反序列化时,可以根据自己的需要,写入或读取指定的实例。使用这种机制,需要在实现Serializable接口的类中添加两个方法:

    private Object readResolve()   //如果用户在序列化类中添加了该方法,则在进行反序列化时,使用该方法返回的对象,作为反序列化对象。

    private Object writeReplace()   //如果用户在序列化类中添加了该方法,则在进行序列化时,序列化该类返回的对象。

再看使用了该机制的单例模式:

public class Singleton implements Serializable {

    private volatile static Singleton mInstance;
    private Singleton() {
    }

    public static Singleton getInstance() {
        if (mInstance == null) {
            synchronized (Singleton.class) {
                if (mInstance == null) {
                    mInstance = new Singleton();
                }
            }
        }
        return mInstance;
    }

    private Object readResolve() {
        return getInstance();
    }

    private Object writeReplace() {
        return getInstance();
    }
}
로그인 후 복사

 此时的通过反序列化得到的对象也是同一个,即单例模式依然有效!

相关文章:

Java序列化Serializable和Externalizable区别的示例代码

java 序列化对象 serializable 读写数据的实例

php—Serializable接口

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿
회사 소개 부인 성명 Sitemap
PHP 중국어 웹사이트:공공복지 온라인 PHP 교육,PHP 학습자의 빠른 성장을 도와주세요!