Подтвердить что ты не робот

Как определить, изменяет ли метод Java объект, переданный как параметр

Я родом из С++, и сейчас я изучаю Java. Один вопрос возник, когда я попытался использовать некоторые сторонние библиотеки. Как определить, вызывает ли вызов метода, ссылающегося на объектную ссылку, как параметр, изменяет объект? В С++ это понятно благодаря использованию ключевого слова const. Если сигнатура метода:

void foo(Boo& boo);

Я знаю, что ссылочный объект может быть изменен, а если подпись метода:

void foo(const Boo& boo);

Компилятор гарантирует, что ссылочный объект не будет изменен.

Я не видел ничего похожего на Java, поскольку только сама ссылка может быть объявлена ​​окончательной, а не ссылочным объектом, а окончательный аргумент не имеет большого смысла в первую очередь, поскольку он все равно передается значением. Поэтому, когда я вижу такой метод, как:

void foo(Boo boo) {...}

Как определить, изменен ли объект, на который ссылается boo внутри тела функции (возможно, используя аннотации)? Если нет способа узнать, существует ли какая-то широко используемая конвенция или некоторые лучшие практики, чтобы избежать путаницы и ошибок?

4b9b3361

Ответ 1

как определить, изменен ли объект, на который ссылается boo внутри тела функции (возможно, используя аннотации)?

Единственный способ - прочитать код, к сожалению.

Если нет способа узнать, существует ли какая-то широко используемая конвенция или некоторые лучшие практики, чтобы избежать путаницы и ошибок?

Общим соглашением является передача объекта, который не может быть изменен, при необходимости используя обертку. Это гарантирует, что класс не может изменить объект.

List<String> readOnly = Collections.unmodifiableList(list);

Если объект Cloneable, вы также можете использовать clone(), но другим распространенным подходом является использование копии.

List<String> readOnly = new ArrayList<>(list);

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

Ответ 2

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

Ответ 3

ПРИМЕЧАНИЕ: этот ответ является более подробной версией

Вы также можете писать аннотации чистоты или побочных эффектов в своем коде - mernst

Существует Checker Framework среди различных вещей, которые он может проверять во время компиляции через аннотации, это IJG Immutablity checker. Эта проверка позволяет комментировать ссылки на объекты с помощью @Immutable или @ReadOnly.

Проблема в том, что вам часто приходилось аннотировать библиотеку самостоятельно. Чтобы облегчить вашу задачу, Checker Framework может автоматически вывести часть аннотаций; вам все равно придется самому заняться.

Ответ 4

Анализ побочных эффектов не встроен в язык Java.

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

Вы можете использовать инструмент вывода (1, 2, 3), чтобы определить, является ли ваш код побочным эффектом параметра.

Вы также можете записать аннотации чистоты или побочных эффектов в свой код, а затем использовать инструмент проверки/проверки (1, 2), чтобы ваш код соответствовал написанным аннотациям.

Все вышеперечисленные инструменты имеют ограничения, но вы можете найти их полезными. Если вы знаете другие инструменты, укажите их в комментариях.

Ответ 5

Как определить, если объект, на который ссылается boo, изменяется внутри тело функции (возможно, используя аннотации)?

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

Если нет способа узнать, существует ли какая-то широко используемая конвенция или некоторые рекомендации, чтобы избежать путаницы и ошибок?

Здесь появляется название метода. Двигаясь вперед с соглашением об именах метода, мы должны взглянуть на некоторые декларации методов, которые явно убеждают вас в том, что ваш Object вообще не будет изменен.

Например, вы знаете, что Arrays.copyOf не изменит ваш фактический массив, System.out.println(boo) не изменит ваш boo

Имена методов - это реальное оружие, обеспечивающее пользователю максимально возможную информацию. (Да, это всегда невозможно, но достаточно хорошая практика.)

Рассмотрим в вашем случае, что printBoo будет только печатать, copyBoo будет копировать только clearBoo будет reset все атрибуты, checkAndCreateNewBoo проверит ваш boo Object и создаст новый если требуется.

Итак, в конечном счете, если мы сможем использовать их надлежащим образом, вызывающий может быть уверен в том, что Object останется неизменным после вызова метода.

Ответ 6

Как все говорят, предпочитайте использовать неизменяемые объекты, а также избегайте методов void

Доступные цели таких методов

void foo(Boo boo) {...}

должны изменить состояние самого объекта или изменить объект, переданный как параметр

void completOrder(Order order) { ... }
//or
void parserTokenEnded(String str) { ... }

Ответ 7

Существует способ, что разработчик метода должен отмечать параметр как final, если он не будет изменять параметр.

     public void test(final Object param)

Однако очень мало людей следуют за этим, так что это трудно понять. Однако хороший программист следует этому правилу, особенно написав api. Если вы хотите написать метод и разоблачить его. Сделайте param final, чтобы указать, что переданный объект не будет изменен.