Каноническая форма поля
Я изучаю Эффективную Java, Пункт 8 (Соблюдайте общий контракт, когда переопределение равно). Автор объяснил это довольно четко, но все же некоторые части не настолько проработаны.
В этом примере он рассматривает класс CaseInsensitiveString, определенный как:
public final class CaseInsensitiveString {
private final String s;
public CaseInsensitiveString(String s) {
if (s == null)
throw new NullPointerException();
this.s = s;
}
// Broken - violates symmetry!
@Override
public boolean equals(Object o) {
if (o instanceof CaseInsensitiveString)
return s.equalsIgnoreCase(((CaseInsensitiveString) o).s);
if (o instanceof String) // One-way interoperability!
return s.equalsIgnoreCase((String) o);
return false;
}
// ... // Remainder omitted
}
В конце статьи он говорит:
Для некоторых классов, таких как CaseInsensitiveString выше, сравнение полей является более сложным, чем простые тесты на равенство. Если это так, вы можете сохранить каноническую форму поля, поэтому метод equals может выполнять дешевые точные сравнения по этим каноническим формам, а не более дорогостоящие неточные сравнения. Этот метод наиболее подходит для неизменяемых классов (пункт 15); если объект может измениться, вы должны поддерживать каноническую форму в актуальном состоянии.
Я искал этот термин и обнаружил, что он в основном означает стандартное представление чего-либо, например, абсолютный путь без каких-либо символических ссылок для файла в каталоге. Но я не могу понять использование "канонической" формы для этого класса, которая могла бы помочь здесь. Какие-либо предложения?
1 ответ
Я думаю, что в этом конкретном примере каноническая форма могла бы хранить строчную или строчную версию String и делать сравнения с ней.
private final String s;
public CaseInsensitiveString(String s) {
//for real code probably use locale version
this.s = s.toLowerCase();
}
Это делает сравнение равенства дешевле, потому что мы можем делать точные сравнения строк вместо более дорогих equalsIgnoreCase
// Broken - violates symmetry!
@Override
public boolean equals(Object o) {
if (o instanceof CaseInsensitiveString)
return s.equals(((CaseInsensitiveString) o).s);
if (o instanceof String) // One-way interoperability!
return s.equals((String) o);
return false;
}