¿Qué significa el término "forma canónica" o "representación canónica" en Java?

90

A menudo he escuchado este término, pero nunca lo he entendido realmente.

¿Qué significa? ¿Alguien puede dar algunos ejemplos / señalarme algunos enlaces?

EDITAR: Gracias a todos por las respuestas. ¿Puede también decirme cómo la representación canónica es útil en rendimiento igual (), como se indica en Effective Java?

Shivasubramanian A
fuente

Respuestas:

56

Wikipedia apunta al término Canonicalización .

Un proceso para convertir datos que tienen más de una representación posible en una representación canónica "estándar". Esto se puede hacer para comparar diferentes representaciones para la equivalencia, para contar el número de estructuras de datos distintas, para mejorar la eficiencia de varios algoritmos eliminando cálculos repetidos, o para hacer posible imponer un orden de clasificación significativo.

El ejemplo de Unicode tenía más sentido para mí:

Las codificaciones de longitud variable en el estándar Unicode, en particular UTF-8, tienen más de una codificación posible para la mayoría de los caracteres comunes. Esto hace que la validación de cadenas sea más complicada, ya que se deben considerar todas las posibles codificaciones de cada carácter de cadena. Una implementación de software que no considera todas las codificaciones de caracteres corre el riesgo de aceptar cadenas consideradas inválidas en el diseño de la aplicación, lo que podría causar errores o permitir ataques. La solución es permitir una única codificación para cada carácter. La canonicalización es entonces el proceso de traducir cada carácter de cadena a su codificación única permitida. Una alternativa es que el software determine si una cadena está canonicalizada y luego la rechace si no lo está. En este caso, en un contexto cliente / servidor, la canonicalización sería responsabilidad del cliente.

En resumen, una forma estándar de representación de datos. Desde este formulario, puede convertir a cualquier representación que pueda necesitar.

Brian Gianforcaro
fuente
64

Creo que hay dos usos relacionados de canónico: formas e instancias.

Una forma canónica significa que los valores de un tipo particular de recurso se pueden describir o representar de múltiples formas, y una de esas formas se elige como la forma canónica preferida. (Esa forma está canonizada , como los libros que llegaron a la Biblia, y las otras formas no). Un ejemplo clásico de una forma canónica son las rutas en un sistema de archivos jerárquico, donde se puede hacer referencia a un solo archivo de varias maneras. :

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

La definición clásica de la representación canónica de ese archivo sería la última ruta. Con rutas locales o relativas, no puede identificar globalmente el recurso sin información contextual. Con las rutas absolutas puede identificar el recurso, pero no puede saber si dos rutas se refieren a la misma entidad. Con dos o más rutas convertidas a sus formas canónicas, puede hacer todo lo anterior, además de determinar si dos recursos son iguales o no, si eso es importante para su aplicación (resuelva el problema del alias ).

Tenga en cuenta que la forma canónica de un recurso no es una cualidad de esa forma particular en sí; puede haber múltiples formas canónicas posibles para un tipo dado, como rutas de archivo (digamos, lexicográficamente en primer lugar de todas las posibles rutas absolutas). Una forma simplemente se selecciona como forma canónica por una razón de aplicación en particular, o tal vez arbitrariamente para que todos hablen el mismo idioma.

Forzar objetos en sus instancias canónicas es la misma idea básica, pero en lugar de determinar una "mejor" representación de un recurso, elige arbitrariamente una instancia de una clase de instancias con el mismo "contenido" que la referencia canónica, luego convierte todas las referencias a objetos equivalentes para usar la única instancia canónica.

Esto se puede utilizar como una técnica para optimizar tanto el tiempo como el espacio. Si hay varias instancias de objetos equivalentes en una aplicación, al forzarlos a que se resuelvan como la única instancia canónica de un valor particular, puede eliminar todos menos uno de cada valor, ahorrando espacio y posiblemente tiempo, ya que ahora puede comparar aquellos valores con identidad de referencia (==) en contraposición a la equivalencia de objeto ( equals()método).

Un ejemplo clásico de optimización del rendimiento con instancias canónicas es contraer cadenas con el mismo contenido. String.intern()Se garantiza que la invocación de dos cadenas con la misma secuencia de caracteres devolverá el mismo objeto String canónico para ese texto. Si pasa todas sus cadenas a través de ese canonicalizador, sabrá que las cadenas equivalentes son en realidad referencias de objetos idénticas, es decir, alias

Los tipos de enumeración en Java 5.0+ obligan a todas las instancias de un valor de enumeración particular a usar la misma instancia canónica dentro de una VM, incluso si el valor está serializado y deserializado. Es por eso que puede usar if (day == Days.SUNDAY)con impunidad en java si Dayses un tipo enum. Hacer esto para sus propias clases es ciertamente posible, pero hay que tener cuidado. Lea Effective Java de Josh Bloch para obtener detalles y consejos.

Dov Wasserman
fuente
31

Un buen ejemplo para comprender la "forma / representación canónica" es mirar la definición de tipo de datos del esquema XML de "booleano":

  • la "representación léxica" de boolean puede ser una de: {true, false, 1, 0}mientras que
  • la "representación canónica" sólo puede ser una de {true, false}

Esto, en esencia, significa que

  • "true"y "1"ser mapeado a la repr. canónica. "true"y
  • "false"y "0"ser mapeado a la repr. canoncial."false"

consulte la definición de tipo de datos del esquema XML w3 para booleano

Michael Marton
fuente
28

La palabra "canónico" es solo un sinónimo de "estándar" o "habitual". No tiene ningún significado específico de Java.

Dónal
fuente
3
canonical tiene un significado más rico que el estándar o la OMI habitual.
calamar
20

reducido a la forma más simple y significativa sin perder la generalidad

Jaime
fuente
5

Una manera fácil de recordarlo es la forma en que se usa "canónico" en los círculos teológicos, la verdad canónica es la verdad real, así que si dos personas la encuentran, han encontrado la misma verdad. Lo mismo ocurre con la instancia canónica. Si cree que ha encontrado dos de ellos (es decir a.equals(b)), en realidad solo tiene uno (es decir a == b). Entonces la igualdad implica identidad en el caso de objeto canónico.

Ahora para la comparación. Ahora tiene la opción de usar a==b o a.equals(b) , ya que producirán la misma respuesta en el caso de una instancia canónica, pero a == b es una comparación de la referencia (la JVM puede comparar dos números extremadamente rápido ya que son solo dos patrones de 32 bits comparados a lo a.equals(b)que es una llamada a un método e implica más gastos generales.

Chris Mawata
fuente
2

Otro buen ejemplo podría ser: tienes una clase que admite el uso de coordenadas cartesianas (x, y, z), esféricas (r, theta, phi) y cilíndricas (r, phi, z). Con el fin de establecer la igualdad (método de igualdad), probablemente desee convertir todas las representaciones en una representación "canónica" de su elección, por ejemplo, coordenadas esféricas. (O tal vez desee hacer esto en general, es decir, usar una representación interna). No soy un experto, pero esto se me ocurrió tal vez como un buen ejemplo concreto.

Kimberley Coburn
fuente
0

La representación canónica significa ver el personaje en un estilo diferente, por ejemplo, si escribo una letra A significa que otra persona puede escribir la letra A en un estilo diferente :)

Esto es de acuerdo con el CAMPO DE RECONOCIMIENTO DE CARÁCTER ÓPTICO

SASIKALA
fuente
0

Una forma canónica significa una representación naturalmente única del elemento

Maksym Ovsianikov
fuente
0

Las preguntas del OP sobre la forma canónica y cómo se puede mejorar el rendimiento del equalsmétodo se pueden responder ampliando el ejemplo proporcionado en Effective Java.

Considere la siguiente clase:

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);
  }
}

El equalsmétodo de este ejemplo tiene un costo adicional al usar Stringel equalsIgnoreCasemétodo de. Como se menciona en el texto

es posible que desee almacenar una forma canónica del campo para que el método de iguales pueda realizar una comparación exacta barata de las formas canónicas en lugar de una comparación no estándar más costosa.

¿Qué quiere decir Joshua Bloch cuando dice forma canónica ? Bueno, creo que la respuesta concisa de Dónal es muy apropiada. Podemos almacenar el Stringcampo subyacente en el CaseInsensitiveStringejemplo de una manera estándar , quizás la forma mayúscula de String. Ahora, puede hacer referencia a esta forma canónica de CaseInsensitiveString, su variante en mayúsculas y realizar evaluaciones económicas en sus métodos equalsy hashcode.

La daga de Gilbert Arenas
fuente
0

Datos canónicos en RDBMS, datos gráficos;
Piense como "Normalización" o "Forma normal" de un dato en un RDBMS. Los mismos datos existen en diferentes tablas, representados con un identificador único y mapeados en diferentes tablas.
o
Piense en una forma única de un dato en Graph Database que se represente en muchos triples.

El principal beneficio de esto es hacer que Dml (manipulación de datos) sea más eficiente, ya que puede insertar (insertar / actualizar) solo un valor en lugar de muchos.

Alper t. Turker
fuente