우리는 직렬화를 많이 사용하며 사용하는 모든 객체에 직렬화 가능 태그를 지정해야하는 것은 부담이됩니다. 특히 우리가 실제로 변경할 수없는 제 3 자 클래스 일 때.
질문은 : Serializable은 빈 인터페이스이고 Java는 일단 추가하면 강력한 직렬화를 제공 implements Serializable
하기 때문에 모든 것을 직렬화 가능하게 만들지 않은 이유는 무엇입니까?
내가 무엇을 놓치고 있습니까?
우리는 직렬화를 많이 사용하며 사용하는 모든 객체에 직렬화 가능 태그를 지정해야하는 것은 부담이됩니다. 특히 우리가 실제로 변경할 수없는 제 3 자 클래스 일 때.
질문은 : Serializable은 빈 인터페이스이고 Java는 일단 추가하면 강력한 직렬화를 제공 implements Serializable
하기 때문에 모든 것을 직렬화 가능하게 만들지 않은 이유는 무엇입니까?
내가 무엇을 놓치고 있습니까?
답변:
직렬화에는 함정이 있습니다. 이 형식의 자동 직렬화 지원은 클래스 내부를 공용 API의 일부로 만듭니다 (이것이 javadoc 이 클래스 의 지속 된 형식을 제공하는 이유 입니다 ).
장기 지속성을 위해 클래스는이 양식을 디코딩 할 수 있어야하며, 이는 클래스 디자인에 적용 할 수있는 변경 사항을 제한합니다. 이것은 캡슐화를 깨뜨립니다.
직렬화는 보안 문제로 이어질 수도 있습니다. 참조가있는 모든 객체를 직렬화 할 수 있으므로 클래스는 일반적으로 할 수없는 데이터에 액세스 할 수 있습니다 (결과 바이트 데이터를 구문 분석하여).
내부 클래스의 직렬화 된 형식이 제대로 정의되지 않는 것과 같은 다른 문제가 있습니다.
모든 클래스를 직렬화 가능하게 만들면 이러한 문제가 악화됩니다. 체크 아웃 효과적인 자바 Second Edition의 , 특히 항목 74 : 직렬화를 적절하게 구현합니다 .
이번에는 Java와 .Net 사람들이 모두 잘못 알고 있다고 생각합니다. 기본적으로 모든 것을 직렬화 할 수 있도록하고 대신 안전하게 직렬화 할 수없는 클래스 만 표시하면되었을 것입니다.
예를 들어 Smalltalk (70 년대에 만들어진 언어)에서는 모든 객체가 기본적으로 직렬화 가능합니다. 대부분의 객체가 직렬화하기에 안전하고 일부만 그렇지 않다는 사실을 고려할 때 Java에서 이것이 왜 그렇지 않은지 모르겠습니다.
객체를 직렬화 가능 (인터페이스 사용)으로 표시하는 것은 마술처럼 객체를 직렬화 할 수있는 것이 아닙니다. 계속해서 직렬화 가능 했습니다. 이제 시스템이 스스로 발견 할 수있는 것을 표현했기 때문입니다. 직렬화는 지금의 방식입니다.
디자이너가 내린 잘못된 결정이거나 직렬화가 나중에 고려되었거나 플랫폼이 기본적으로 모든 객체에 대해 안전하고 일관되게 직렬화를 수행 할 준비가되지 않았다고 생각합니다.
Serializable
트릭은 10 ~ 2 년 전에 취해진 잘못된 결정일 뿐이며, 표준 라이브러리의 수집 및 문자열 처리의 일부 결함과 같이 순수한 Java를 다룰 때 성가심에 또 하나 추가됩니다. 다행히 Kryo가 있지만 의존성이며 먼저 찾아야합니다. 이것이 내장 직렬화가 수행되어야하는 방법입니다.
모든 것이 진정으로 직렬화 가능한 것은 아닙니다. 예를 들어 네트워크 소켓 연결을 사용하십시오. 소켓 객체의 데이터 / 상태를 직렬화 할 수 있지만 활성 연결의 본질은 손실됩니다.
implements NotSerializable
:)
Java에서 Serializable의 주요 역할은 기본적으로 다른 모든 객체를 직렬화 불가능하게 만드는 것입니다. 직렬화는 특히 기본 구현에서 매우 위험한 메커니즘입니다. 따라서 C ++의 우정과 마찬가지로 직렬화 가능하게 만드는 데 약간의 비용이 들더라도 기본적으로 꺼져 있습니다.
직렬화는 구조 호환성이 보장되지 않기 때문에 제약 조건과 잠재적 인 문제를 추가합니다. 기본적으로 꺼져있는 것이 좋습니다.
나는 표준 직렬화가 내가 원하는 것을 수행하는 사소한 클래스를 거의 보지 못했다는 것을 인정해야한다. 특히 복잡한 데이터 구조의 경우. 따라서 클래스 직렬화를 적절하게 만드는 데 드는 노력은 인터페이스 추가 비용을 줄여줍니다.
일부 클래스, 특히 파일, 소켓, 스레드 또는 DB 연결과 같이 더 물리적 인 것을 나타내는 클래스의 경우 인스턴스를 직렬화하는 것은 전혀 의미가 없습니다. 다른 많은 경우 직렬화는 고유성 제약 조건을 파괴하거나 단순히 원하지 않는 클래스의 다른 버전의 인스턴스를 처리하도록 강제하기 때문에 문제가 될 수 있습니다.
논란의 여지가 있지만, 기본적으로 모든 것을 Serializable로 만들고 키워드 또는 마커 인터페이스를 통해 클래스를 직렬화 할 수 없게 만드는 것이 더 나았을 수도 있지만,이 옵션을 사용해야하는 사람들은 아마 그것에 대해 생각하지 않을 것입니다. 즉, Serializable을 구현해야하는 경우 Exception이 표시됩니다.
분명히 모든 것이 일부 예비 설계에서 직렬화 가능했지만 보안 및 정확성 문제로 인해 최종 설계는 우리 모두가 알고있는대로 끝났습니다.
출처 : ObjectOutputStream에 작성하기 위해 클래스가 Serializable을 구현해야하는 이유는 무엇입니까? .
특정 클래스의 인스턴스가 직렬화 가능하다는 것을 명시 적으로 설명해야하는 경우 언어는이를 허용해야하는지 생각하게합니다. 단순한 값 객체의 경우 직렬화는 사소하지만 더 복잡한 경우에는 실제로 생각해야합니다.
JVM의 표준 직렬화 지원에 의존하면 모든 종류의 불쾌한 버전 관리 문제에 노출됩니다.
고유성, '실제'리소스에 대한 참조, 타이머 및 기타 여러 유형의 아티팩트는 직렬화 후보가 아닙니다.
직렬화 가능 인터페이스와 직렬화 가능 클래스를 몇 개만 만들어야하는 이유를 이해하려면이 문서를 읽고 저장 프로 시저에서 몇 개의 필드를 제거하려는 경우 일시적인 키워드를 사용할 위치를주의해야합니다.
제 대답은 이것이 정당한 이유가 아니라는 것입니다. 여러분의 의견을 통해 이미 배웠 음을 알 수 있습니다. 다른 언어는 기꺼이 10까지 세고 트리에서 점프하지 않는 모든 것을 직렬화하려고합니다. 객체는 기본적으로 직렬화 가능해야합니다.
따라서 기본적으로해야 할 일은 타사 클래스의 모든 속성을 직접 읽는 것입니다. 또는 그것이 당신을위한 옵션이라면 : 디 컴파일하고 거기에 빌어 먹을 키워드를 넣고 다시 컴파일하십시오.
Java에는 런타임에 따라 다르기 때문에 직렬화 할 수없는 몇 가지가 있습니다. 스트림, 스레드, 런타임 등과 같은 것 및 일부 GUI 클래스 (기본 OS에 연결됨)도 직렬화 할 수 없습니다.
여기에서 다른 답변의 요점에 동의하지만 실제 문제는 역 직렬화에 있습니다. 클래스 정의가 변경되면 역 직렬화가 작동하지 않을 실제 위험이 있습니다. 기존 필드를 수정하지 않는 것은 라이브러리 작성자에게 매우 중요한 약속입니다! API 호환성을 유지하는 것은 그 자체로 충분합니다.
파일이나 다른 미디어에 유지되어야하는 클래스는 JVM이 클래스 객체를 직렬화 할 수 있도록 Serializable 인터페이스를 구현해야합니다. Object 클래스가 직렬화되지 않은 이유는 모든 JVM이 ObjectOutputStream 을 사용할 때만 클래스를 직렬화 한 후 어떤 클래스도 인터페이스를 구현할 필요가 없습니다. 즉, JVM이 직렬화 할 수 있도록 컨트롤이 여전히 내 손에 있음을 의미합니다.
Object 클래스가 기본적으로 직렬화되지 않는 이유는 클래스 버전이 주요 문제이기 때문입니다. 따라서 직렬화에 관심이있는 각 클래스는 명시 적으로 Serializable로 표시하고 버전 번호 serialVersionUID를 제공해야합니다.
경우 의 serialVersionUID는 JVM이 발생하는 이유 후 제공되지 않는 개체를 deserialzing 동안 우리가 예상치 못한 결과를 얻을, 즉 인해 InvalidClassException을 경우 의 serialVersionUID가 일치하지 않습니다. 따라서 모든 클래스는 Serializable 인터페이스 를 구현 하고 serialVersionUID 를 제공 하여 양쪽 끝에 제시된 클래스가 동일한 지 확인해야합니다.