FindBugs хочет, чтобы readObject (...) был закрытым для сериализации, почему? - PullRequest
3 голосов
/ 12 августа 2011

Я запускаю findbugs для некоторого кода, и он говорит, что метод readObject (...) должен быть закрытым, чтобы его можно было вызывать для сериализации / десериализации?Зачем?В чем проблема, если она обнародована?

Ответы [ 5 ]

6 голосов
/ 21 ноября 2012

О том, что readObject()/writeObject() является приватным, вот в чем дело: если ваш класс Bar расширяет некоторый класс Foo; Foo также реализует readObject()/writeObject(), а Bar также реализует readObject()/writeObject().

Теперь, когда объект Bar сериализуется или десериализуется, JVM необходимо автоматически вызвать readObject()/writeObject() для Foo и Bar (т.е. без необходимости явного вызова этих методов суперкласса). Однако если эти методы не являются частными, они становятся переопределенными, и JVM больше не может вызывать методы суперкласса для объекта подкласса.

Следовательно, они должны быть частными!

3 голосов
/ 12 августа 2011

В современных реализациях Java (по крайней мере, JDK 6–10) классы ObjectInputStream и ObjectOutputStream распознают методы readObject, readObjectNoData и writeObject, только если они объявлены как private иНЕ static.

(Я не смог найти это явно в какой-либо документации, но ограничение явно реализовано в коде.)

Таким образом, независимо от того, является ли оноХорошая идея или нет, но FindBugs правильно указал, что не приватный метод readObject является ошибкой.Он не будет использоваться.

Единственная причина, по которой я хочу сделать этот метод открытым, - сделать его окончательным, чтобы наследующие объекты не могли его использовать.

Iне думайте, что вам следует попытаться сделать это.Поместите примечание в javadoc уровня класса, чтобы сказать, что вы думаете, что подклассы должны и не должны делать.Если кто-то решит реализовать класс, игнорируя этот совет, его проблема состоит в том, чтобы справиться с последствиями.

Проблема с попыткой заставить других людей реализовать подклассы определенным образом заключается в том, что они могут иметьВ случае, если требует , чтобы они действовали по-другому ... по причинам, которые вы не в состоянии понять.Лучше оставить будущим разработчикам свободу делать то, что они хотят, и позволить им нести ответственность за последствия.

1 голос
/ 12 октября 2011

Чтобы ваш метод вызывался objectInputStream.readObject (), вы должны объявить его закрытым:

private void readObject(ObjectInputStream objectInputStream)

Если вы этого не сделаете, ваш метод не будет вызываться (укажите точку останова, чтобы доказать это). Возможно, ваш код работает, но это потому, что используется сериализация по умолчанию.

Возможно, вы захотите сделать это защищенным, чтобы разрешить создание подклассов, но это не нужно. Процесс сериализации автоматически вызывает readObject базового класса перед вызовом readObject конкретного класса. Это происходит, даже если конкретный класс не вызывает:

objectInputStream.defaultReadObject();

... вопреки другим постам, которые я читал в Интернете. То же самое относится и к методам writeObject.

1 голос
/ 12 августа 2011

У вас нет причин вызывать методы сериализации, такие как readObject, а тем более из другого класса. Вы должны минимизировать видимость всего, что можете.

Редактировать: если вы хотите, чтобы подклассы могли изменять поведение, сделайте метод protected ... приемлемым.

1 голос
/ 12 августа 2011

Я не уверен, почему findbugs считает это ошибкой, но я могу догадаться по двум возможным причинам.Публичное чтение readObject нарушает инкапсуляцию, потому что вызывающий код имеет видимость внутренней структуры вашего класса.Кроме того, делая его общедоступным, вы заставляете все производные классы объявлять readObject как public.Поэтому, если класс не является окончательным, вы изменяете контракт на сериализацию.

Я думал, что findbugs может предоставить обоснование для большинства его сообщений.Есть что сказать по этому поводу?

...