2012-07-31 3 views
9

자바 직렬화와 관련된 흥미로운 문제가 발생했습니다.생성자에서 초기화되는지도의 일련 화

Map<String, String> params = new HashMap<String, String>() {{ 
    put("param1", "value1"); 
    put("param2", "value2"); 
}}; 

내가 ObjectOutputStream에있는 파일로 직렬화하려고 :

ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(outputFile)); 
oos.writeObject(params); 

... 내가 java.io 패키지를 얻을

내지도는 다음과 같이 정의 된 경우 것 같다 NotSerializableException입니다.

그러나, 대신 나는지도에 표준 방식으로 값을 넣을 경우 :

Map<String, String> params = new HashMap<String, String>(); 
params.put("param1", "value1"); 
params.put("param2", "value2"); 

... 다음 직렬화 잘 작동합니다.

아무에게도 왜 그런 일이 일어 났으며이 문장들의 차이점은 무엇인지 말해 줄 수 있습니까? 나는 그들이 똑같이 작동해야한다고 생각하지만 분명히 나는 ​​뭔가를 놓치고있다.

답변

10

첫 번째 예는 익명 내부 클래스를 만드는 것입니다. 어떻게?

Map<String, String> params = new HashMap<String, String>() {}; 

HashMap에서 파생 된 새로운 클래스를 만들 것이다 (당신이 방법을 넣을 수있는 다음 괄호에주의를, 회원 등)

지도 초기화는, 따라서 initialiser 블록을 선언

Map<String, String> params = new HashMap<String, String>() { 
                  { // here } 
                  }; 

그리고 모집단 방법을 호출해야합니다.

이 관용구는 괜찮습니다. 이지만 새 개체가 아닌이라는 새 클래스를 만드는 것에 유의해야합니다.

이 클래스는 내부 클래스이기 때문에 포함하는 외부 클래스에 대한 암시 적 this 포인터를 갖습니다. 익명의 클래스는, 직렬화 가능한 클래스로부터 파생 되었기 때문에, 직렬화 가능합니다. 그러나 귀하의 외부 클래스 (포인터에 의해 참조)되지 않습니다.

리플렉션을 통해 XML에 serialize하는 도구는 this 포인터를 발견하고 비슷한 결과를 나타내는 주변 객체를 직렬화하려고 시도합니다.

+1

'static initialiser'는'instance initializer'를 의미합니까? –

+0

그래서 예상되는 둘러싸는 클래스는 무엇입니까? – Shark

+0

@ Eng.Fouad - whoops. 수정 됨 –

0

나는이 제안에 @ 브라이언 애그뉴의 답변을 보완하기 위해 원 :

내가 대상이 약간 다른 동작을 필요로하는 경우를했다, 그래서 당신이에서와 마찬가지로 나는 익명의 내부 클래스와 그 기능을 확장 예. 외부 클래스는 GUI 애플리케이션이었고, 필자는 직렬화 할 필요가 없었기 때문에 @Brian이 말했듯이 익명의 내부 클래스는 확장 가능한 클래스가 있더라도 직렬화 할 수 없습니다.

이 경우에는 클래스를 deserialize하고 다시 serialize 할 때 다른 동작을 정의하기 만하면됩니다.특정 생성자를 가진 클래스가있는 경우, 클래스에서이 같은 방법을 사용하십시오

public FunctionalObject getNewFunctionalObject (String param1, String param2) { 
    // Use an anonymous inner class to extend the behavior 
    return new FunctionalObject (param1, param2) { 
     { 
      // Initialization block code here 
     } 
     // Extended behavior goes here 
    }; 
} 

그래서 당신이 직렬화 복원 할 때, 당신은 전화 같이 할 수 있습니다 :

FunctionalObject fo = (FunctionalObject) objectInputStream.readObject(); 
fo = getNewFunctionalObject(fo.getParam1(), fo.getParam2()); 

직렬화, 이전 개체의 복제본 인 new 개체를 만들어야합니다. 일부 클래스에는이 동작이 내장되어 있으며, 다른 클래스에서는 특별히 정의해야합니다. 당신이 그것을 복제 할 수 있습니다 생성자가있는 경우 클래스가 정의 된 clone 방법이있는 경우 직렬화를 들어, 또는, 당신이 할 수 있습니다 :

objectOutputStream.writeObject (fo.clone()); 

그런 다음, 그 객체의 clone는 더 이상 참조 할 수 없을 것이다 익명 내부 클래스가 아니라 객체의 실제 사본에 대한 참조이며 직렬화 할 수 있습니다. 귀하의 예제의 경우

, 당신은이 작업을 수행 할 수 :

HashMap 클래스 HashMap 그것으로 전달되는 어떤의 복제를 반환하는 생성자를 가지고 있기 때문에이 작동
// Assuming objectOutputStream has already been defined 
Map<String, String> params = new HashMap<String, String>() {{ 
    put("param1", "value1"); 
    put("param2", "value2"); 
}}; 
objectOutputStream.writeObject (new HashMap<String,String> (params)); 

. 그것은 단순한 말을하기위한 많은 말 이었지만, 나는이 조언을 나 자신보다 빨리 나에게 가지기를 바랐다.

관련 문제