Что означает термин «каноническая форма» или «каноническое представление» в Java? - PullRequest
79 голосов
/ 11 ноября 2008

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

Что это значит, и может ли кто-нибудь привести некоторые примеры / указать мне на некоторые ссылки?

РЕДАКТИРОВАТЬ: Спасибо всем за ответы. Не могли бы вы также рассказать мне, как каноническое представление полезно в производительности equals (), как указано в Effective Java?

Ответы [ 10 ]

59 голосов
/ 12 декабря 2008

Я полагаю, что есть два связанных использования канонического: формы и экземпляры.

A каноническая форма означает, что значения определенного типа ресурса могут быть описаны или представлены несколькими способами, и один из этих способов выбран в качестве предпочтительной канонической формы. (Эта форма канонизирована , как книги, которые превратили ее в библию, а другие формы - нет.) Классическим примером канонической формы являются пути в иерархической файловой системе, где один файл может быть ссылаться несколькими способами:

myFile.txt                                   # in current working dir
../conf/myFile.txt                           # relative to the CWD
/apps/tomcat/conf/myFile.txt                 # absolute path using symbolic links
/u1/local/apps/tomcat-5.5.1/conf/myFile.txt  # absolute path with no symlinks

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

Обратите внимание, что каноническая форма ресурса не является качеством этой конкретной формы; может быть несколько возможных канонических форм для данного типа, таких как пути к файлам (скажем, лексикографически прежде всего возможных абсолютных путей). Одна форма просто выбрана в качестве канонической формы по определенной причине применения или, может быть, произвольно, чтобы все говорили на одном языке.

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

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

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

Типы перечислений в Java 5.0+ заставляют все экземпляры определенного значения перечисления использовать один и тот же канонический экземпляр в виртуальной машине, даже если значение сериализуется и десериализуется. Вот почему вы можете безнаказанно использовать if (day == Days.SUNDAY) в java, если Days является типом enum. Делать это для своих собственных занятий, безусловно, возможно, но это необходимо. Прочитайте Effective Java Джоша Блоха для подробностей и советов.

52 голосов
/ 11 ноября 2008

Википедия указывает на термин Канонизация .

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

Пример Unicode имел для меня наибольшее значение:

Кодировки переменной длины в стандарте Unicode, в частности UTF-8, имеют более одной возможной кодировки для наиболее распространенных символов. Это делает проверку строки более сложной, поскольку необходимо учитывать каждую возможную кодировку каждого символа строки. Программная реализация, которая не учитывает все кодировки символов, рискует принять строки, которые считаются недействительными в проекте приложения, что может привести к ошибкам или разрешению атак. Решение состоит в том, чтобы разрешить одну кодировку для каждого символа. Канонизация - это процесс перевода каждого строкового символа в его единственное допустимое кодирование. Альтернатива для программного обеспечения - определить, канонизирована ли строка, а затем отклонить ее, если это не так. В этом случае в контексте клиент / сервер ответственность за канонизацию несет клиент.

Таким образом, стандартная форма представления данных. Из этой формы вы можете преобразовать в любое представление, которое вам может понадобиться.

26 голосов
/ 12 сентября 2012

Хороший пример для понимания «канонической формы / представления» - взглянуть на определение типа данных «логическое» в схеме XML:

  • «лексическое представление» логического значения может быть одним из: {true, false, 1, 0}, тогда как
  • «каноническое представление» может быть только одним из {true, false}

Это, по сути, означает, что

  • "true" и "1" сопоставляются с каноническим репр. "true" и
  • "false" и "0" сопоставляются с каноническим репр. "false"

см. определение типа данных схемы XML w3 для логического значения

25 голосов
/ 11 ноября 2008

Слово "канонический" является просто синонимом слова "стандартный" или "обычный". У него нет специфического для Java значения.

17 голосов
/ 29 июля 2010

приведено к простейшей и наиболее значимой форме без потери общности

4 голосов
/ 02 августа 2012

Легкий способ запомнить это, как «канонический» используется в богословских кругах, каноническая правда - это настоящая правда, поэтому, если два человека найдут ее, они найдут одну и ту же истину. То же самое с каноническим экземпляром. Если вы думаете, что нашли два из них (т.е. a.equals(b)), у вас действительно есть только один (то есть a == b). Таким образом, равенство подразумевает идентичность в случае канонического объекта.

Теперь для сравнения. Теперь у вас есть выбор использования a==b или a.equals(b), так как они будут давать тот же ответ в случае канонического экземпляра, но a == b - это сравнение ссылки (JVM может сравнить два числа очень быстро, так как они представляют собой всего лишь два 32-битных шаблона по сравнению с a.equals(b), который является вызовом метода и требует больших накладных расходов.

2 голосов
/ 15 июня 2012

Другим хорошим примером может быть: у вас есть класс, который поддерживает использование декартовых (x, y, z), сферических (r, theta, phi) и цилиндрических координат (r, phi, z). В целях установления равенства (метод equals) вы, вероятно, захотите преобразовать все представления в одно «каноническое» представление по вашему выбору, например, сферические координаты. (Или, может быть, вы захотите сделать это в целом - то есть использовать одно внутреннее представление.) Я не эксперт, но мне это показалось, может быть, хорошим конкретным примером.

0 голосов
/ 19 октября 2018

На вопросы ОП о канонической форме и о том, как она может улучшить производительность метода equals, можно ответить, расширив пример, предоставленный в Effective Java.

Рассмотрим следующий класс:

public final class CaseInsensitiveString {

  private final String s;

  public CaseInsensitiveString(String s) {
    this.s = Objects.requireNonNull(s);
  }

  @Override 
  public boolean equals(Object o) {
    return o instanceof CaseInsensitiveString && ((CaseInsensitiveString) o).s.equalsIgnoreCase(s);
  }
}

Метод equals в этом примере увеличил стоимость, используя метод String 'equalsIgnoreCase. Как указано в тексте

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

Что означает Джошуа Блох, когда говорит каноническая форма ? Ну, я думаю, что краткий ответ Доналя очень уместен. Мы можем хранить базовое поле String в примере CaseInsensitiveString стандартным способом , возможно, в верхнем регистре String. Теперь вы можете ссылаться на эту каноническую форму CaseInsensitiveString, ее заглавный вариант, и выполнять дешевые оценки в ваших equals и hashcode методах.

0 голосов
/ 17 февраля 2016

Каноническая форма означает естественно уникальное представление элемента

0 голосов
/ 14 сентября 2010

каноническое представление означает просмотр персонажа в другом стиле например, если я пишу букву А, это означает, что другой человек может написать букву А в другом стиле:)

Это соответствует ПОЛЕ ОПТИЧЕСКОГО ПРИЗНАНИЯ ХАРАКТЕРА

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...