Pytanie Dlaczego przetwarzana wewnętrznie klasa nie podlega przekształceniu do postaci szeregowej?


Poniższy kod:

public class TestInnerClass {

    public static void main(String[] args) throws IOException {
        new TestInnerClass().serializeInnerClass();
    }

    private void serializeInnerClass() throws IOException {
        File file = new File("test");
        InnerClass inner = new InnerClass();
        new ObjectOutputStream(new FileOutputStream(file)).writeObject(inner);
    }

    private class InnerClass implements Serializable {

        private static final long serialVersionUID = 1L;

    }

}

zgłasza następujący wyjątek:

Exception in thread "main" java.io.NotSerializableException: TestInnerClass

Domyślam się, że klasa wewnętrzna ma TestInnerClass.this pole, które umożliwia mu prywatny dostęp TestInnerClasspola i metody. Deklaracja wewnętrznej klasy statycznej rozwiązuje to, ale co gdyby InnerClass potrzebuje tego dostępu? Czy istnieje sposób na serializację niestatycznej klasy wewnętrznej bez klasy otaczającej, np. przez odniesienie do klasy zewnętrznej transient?

edit: na przykład dostęp do zewnętrznej klasy może być potrzebny tylko przed serializacją. OK, kompilator nie może o tym wiedzieć, ale pomyślałem, że właśnie dlatego transient słowo kluczowe istnieje.


18
2017-08-22 08:39


pochodzenie


czy próbowałeś zadeklarować wewnętrzne statyczne klasy? private static class InnerClass - gnat


Odpowiedzi:


co jeśli InnerClass potrzebuje tego dostępu?

Następnie potrzebuje zewnętrznej instancji klasy i musi być serializowana wraz z wewnętrzną klasą.

Czy istnieje sposób na serializację niestatycznej klasy wewnętrznej bez klasy otaczającej, np. przez odniesienie do zewnętrznej klasy?

Nie. Co by się stało, gdyby deserializować taką klasę, a następnie spróbuj wywołać metodę instancji klasy zewnętrznej? ZA NullPointerException?


22
2017-08-22 08:49



W mojej sytuacji klasa wewnętrzna potrzebuje dostępu, zanim będzie serializowana (nie po deserializacji). Później służy tylko jako superklasa, która nie zna klasy zewnętrznej. - tb189
@ tb189: Zawsze możesz zerwać zależność niestatyczną, dodając pole transient TestInnerClass parentClass do InnerClass i zajmij się tym podczas deserializacji. - dma_k
Byłby to rzeczywiście sposób radzenia sobie z tym i przypomina przejściowe odniesienie do TestInnerClass.this. - tb189
@dma_k outerClass, masz na myśli. outer! = parent. Chociaż masz rację, że jest to rozwiązanie. - Boann
@Boann: W powyższym przykładzie InnerClass jest wewnętrzną klasą, TestInnerClass jest klasą zewnętrzną. Jeśli podana klasa wewnętrzna byłaby klasą zagnieżdżoną, wyjątek nie zostałby podniesiony, ponieważ klasa zagnieżdżona nie ma żadnego niejawnego odwołania do jej klasy kontenera. Widzieć ten post dotyczące terminologii. - dma_k


a co powiesz na możliwość serializacji TestInnerClass?

public class TestInnerClass implements Serializable { }

1
2017-08-22 08:43



Jest to możliwe, ale nie zawsze jest pożądane, ponieważ powoduje to dodanie dużej ilości danych do klasy zserializowanej. - tb189
@EJP: zawsze istnieją rozwiązania, które mogą być bardziej preferowane (oddzielające części klasy wewnętrznej, które potrzebują dostępu, a następnie przesyłają je do statycznej klasy serializowalnej, używając pola testowego TransientClass, zachowując inny obiekt serializowalny w klasie wewnętrznej). Oznaczałoby to również, że wszystkie pola w klasie zewnętrznej są przejściowe, co wydaje się wadą konstrukcyjną. Nie dlatego, że obecna sytuacja nie działa, aby pierwsza alternatywa / hack była natychmiast używana. - tb189


InnerClass nie może być serializowany, ponieważ aby go utworzyć (wymagane podczas deserializacji), potrzebujesz odwołania do instancji klasy zewnętrznej

Instancje klas wewnętrznych nie mogą istnieć bez instancji klasy zewnętrznej.

to znaczy

OuterClass o = new OuterClass();
OuterClass.InnerClass o_i = o.new InnerClass();

Jeśli użyjesz statycznej klasy wewnętrznej, możliwe będzie serializowanie statycznej klasy wewnętrznej. Instancje klas wewnętrznych mogą być tworzone samodzielnie.

to znaczy

OuterClass o = new OuterClass();
OuterClass.InnerClass i = new OuterClass.InnerClass();

1
2018-06-29 07:20



Być może stworzenie githubu lub pełnego odtwarzalnego przykładu byłoby miłe, nie sądzisz? - Adonis