Java массивы создают несколько проблем для записей, и это добавляет ряд ограничений к дизайну. Массивы являются изменяемыми, и их семантика равенства (унаследованная от Object) является идентичностью, а не содержимым.
Основная проблема c в вашем примере заключается в том, что sh означает, что equals()
для массивов означает равенство содержимого, а не ссылку на равенство. Семантика (по умолчанию) для equals()
для записей основана на равенстве компонентов; в вашем примере две Foo
записи, содержащие разные массивы , различаются , и запись ведет себя правильно. Проблема в том, что вы просто сравнили равенство.
Тем не менее, вы можете объявить запись с нужной вам семантикой, это просто займет больше работы, и вы можете почувствовать, что это слишком много работы. Вот запись, которая делает то, что вы хотите:
record Foo(String[] ss) {
Foo { ss = ss.clone(); }
String[] ss() { return ss.clone(); }
boolean equals(Object o) {
return o instanceof Foo
&& Arrays.equals(((Foo) o).ss, ss);
}
int hashCode() { return Objects.hash(Arrays.hashCode(ss)); }
}
Это защитная копия на входе (в конструкторе) и на выходе (в методе доступа), а также настройка Семантика равенства для использования содержимого массива. Это поддерживает инвариант, требуемый в суперклассе java.lang.Record
, который «разбивая запись на ее компоненты и восстанавливая компоненты в новую запись, дает равную запись».
Вы вполне могли бы сказать: «Но это слишком много работы, я хотел использовать записи, чтобы мне не приходилось печатать все эти вещи». Но записи не являются в первую очередь инструментом syntacti c (хотя они синтаксически более приятны), они являются инструментом semanti c: записи являются именными кортежами . В большинстве случаев компактный синтаксис также дает желаемую семантику, но если вам нужна другая семантика, вам придется проделать дополнительную работу.