Co oznacza termin „forma kanoniczna” lub „reprezentacja kanoniczna” w języku Java?


90

Często słyszałem, jak używano tego terminu, ale tak naprawdę nigdy go nie rozumiałem.

Co to znaczy i czy ktoś może podać jakieś przykłady / wskazać mi jakieś linki?

EDYCJA: Dziękuję wszystkim za odpowiedzi. Czy możesz mi również powiedzieć, w jaki sposób reprezentacja kanoniczna jest przydatna w wydajności equals (), zgodnie z opisem w Efektywna Java?

Odpowiedzi:


56

Wikipedia wskazuje na termin „ kanonizacja” .

Proces przekształcania danych, które mają więcej niż jedną możliwą reprezentację, na „standardową” reprezentację kanoniczną. Można to zrobić, aby porównać różne reprezentacje pod względem równoważności, policzyć liczbę różnych struktur danych, poprawić wydajność różnych algorytmów poprzez wyeliminowanie powtarzających się obliczeń lub umożliwić narzucenie sensownej kolejności sortowania.

Unicode przykład wykonany największy sens do mnie:

Kodowania o zmiennej długości w standardzie Unicode, w szczególności UTF-8, mają więcej niż jedno możliwe kodowanie dla większości typowych znaków. To sprawia, że ​​sprawdzanie poprawności ciągu jest bardziej skomplikowane, ponieważ należy wziąć pod uwagę każde możliwe kodowanie każdego znaku ciągu. Implementacja oprogramowania, która nie uwzględnia wszystkich kodowań znaków, stwarza ryzyko akceptowania ciągów uznanych za nieprawidłowe w projekcie aplikacji, co może powodować błędy lub umożliwić ataki. Rozwiązaniem jest umożliwienie jednego kodowania dla każdego znaku. Kanonizacja jest zatem procesem tłumaczenia każdego znaku ciągu na jego pojedyncze dozwolone kodowanie. Alternatywą jest to, że oprogramowanie określa, czy ciąg jest kanonizowany, a następnie odrzuca go, jeśli nie jest. W tym przypadku w kontekście klient / serwer za kanonizację odpowiada klient.

Podsumowując, standardowa forma reprezentacji danych. Z tego formularza możesz następnie przekonwertować na dowolną reprezentację, której możesz potrzebować.


64

Uważam, że istnieją dwa powiązane zastosowania kanoniczne: formy i instancje.

A postaci kanonicznej oznacza, że wartości określonego typu środków mogą być opisane lub przedstawione na wiele sposobów, jeden z tych sposobów jest wybrana jako uprzywilejowanych postaci kanonicznej. (Forma ta jest kanonizowana , podobnie jak książki, które wprowadziły ją do Biblii, a inne nie są). Klasycznym przykładem formy kanonicznej są ścieżki w hierarchicznym systemie plików, gdzie do pojedynczego pliku można się odwoływać na wiele sposobów. :

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

Klasyczna definicja kanonicznej reprezentacji tego pliku byłaby ostatnią ścieżką. W przypadku ścieżek lokalnych lub względnych nie można globalnie zidentyfikować zasobu bez informacji kontekstowych. Dzięki ścieżkom bezwzględnym można zidentyfikować zasób, ale nie można stwierdzić, czy dwie ścieżki odnoszą się do tej samej jednostki. Mając dwie lub więcej ścieżek przekonwertowanych na ich formy kanoniczne, możesz wykonać wszystkie powyższe czynności, a także określić, czy dwa zasoby są takie same, czy nie, jeśli jest to ważne dla Twojej aplikacji (rozwiąż problem z aliasowaniem ).

Należy zauważyć, że forma kanoniczna zasobu nie jest cechą samej tej konkretnej formy; może istnieć wiele możliwych form kanonicznych dla danego typu, takich jak ścieżki do plików (powiedzmy, przede wszystkim leksykograficznie możliwe ścieżki bezwzględne). Jeden formularz jest po prostu wybierany jako forma kanoniczna z konkretnego powodu aplikacji lub może dowolnie, aby wszyscy mówili tym samym językiem.

Wmuszanie obiektów do ich instancji kanonicznych jest tą samą podstawową ideą, ale zamiast określać jedną „najlepszą” reprezentację zasobu, arbitralnie wybiera jedną instancję klasy instancji o tej samej „treści” co odwołanie kanoniczne, a następnie konwertuje wszystkie odwołania do równoważnych obiektów, aby użyć jednej instancji kanonicznej.

Można to wykorzystać jako technikę optymalizacji czasu i przestrzeni. Jeśli w aplikacji istnieje wiele wystąpień równoważnych obiektów, to zmuszając je wszystkie do rozstrzygnięcia jako pojedynczej instancji kanonicznej określonej wartości, możesz wyeliminować wszystkie z wyjątkiem jednej wartości, oszczędzając miejsce i prawdopodobnie czas, ponieważ możesz teraz porównać te wartości z tożsamością odniesienia (==) w przeciwieństwie do równoważności obiektu ( equals()metoda).

Klasycznym przykładem optymalizacji wydajności za pomocą instancji kanonicznych jest zwijanie ciągów o tej samej zawartości. Wywołanie String.intern()dwóch ciągów o tej samej sekwencji znaków gwarantuje zwrócenie tego samego kanonicznego obiektu String dla tego tekstu. Jeśli przepuszczasz wszystkie swoje ciągi przez ten kanonizator, wiesz, że równoważne ciągi są w rzeczywistości identycznymi odwołaniami do obiektów, tj. Aliasami

Typy wyliczeń w Javie 5.0+ wymuszają na wszystkich wystąpieniach określonej wartości wyliczenia używanie tego samego wystąpienia kanonicznego w obrębie maszyny wirtualnej, nawet jeśli wartość jest serializowana i deserializowana. Dlatego możesz if (day == Days.SUNDAY)bezkarnie używać w Javie, jeśli Daysjest to typ wyliczeniowy. Robienie tego na własnych zajęciach jest z pewnością możliwe, ale należy zachować ostrożność. Przeczytaj Effective Java autorstwa Josha Blocha, aby uzyskać szczegółowe informacje i porady.


31

Dobrym przykładem zrozumienia „formy / reprezentacji kanonicznej” jest przyjrzenie się definicji typu danych schematu XML „boolean”:

  • „reprezentacją leksykalną” wartości logicznej może być: {true, false, 1, 0}podczas gdy
  • „reprezentacja kanoniczna” może być tylko jedną z {true, false}

To w istocie oznacza, że

  • "true"i "1"zostań zmapowany do kanonicznego repr. "true"i
  • "false"i "0"zostań zmapowany do kanonicznego rep."false"

zobacz definicję typu danych schematu XML w3 dla wartości logicznych


28

Słowo „kanoniczny” jest po prostu synonimem „standardowego” lub „zwykłego”. Nie ma żadnego znaczenia specyficznego dla języka Java.


3
canonical ma bogatsze znaczenie niż standardowa lub zwykła IMO.
kałamarnica

20

zredukowane do najprostszej i najbardziej znaczącej formy bez utraty ogólności


5

Łatwym sposobem zapamiętania tego jest sposób, w jaki termin „kanoniczny” jest używany w kręgach teologicznych, prawda kanoniczna jest prawdą prawdziwą, więc jeśli dwie osoby ją znajdą, to znaleźli tę samą prawdę. To samo z instancją kanoniczną. Jeśli myślisz, że znalazłeś dwa z nich (tj. a.equals(b)), Tak naprawdę masz tylko jeden (tj a == b.). Tak więc równość implikuje tożsamość w przypadku przedmiotu kanonicznego.

Teraz do porównania. Możesz teraz użyć a==b lub a.equals(b) , ponieważ dadzą tę samą odpowiedź w przypadku wystąpienia kanonicznego, ale a == b jest porównaniem odniesienia (JVM może bardzo szybko porównać dwie liczby, ponieważ są one tylko dwoma 32-bitowymi wzorcami porównanymi do a.equals(b)którego jest wywołaniem metody i wiąże się z większym narzutem.


2

Innym dobrym przykładem może być: masz klasę, która obsługuje użycie współrzędnych kartezjańskich (x, y, z), sferycznych (r, theta, phi) i cylindrycznych (r, phi, z). W celu ustalenia równości (metoda równości) prawdopodobnie chciałbyś przekonwertować wszystkie reprezentacje na jedną wybraną reprezentację „kanoniczną”, np. Współrzędne sferyczne. (A może chciałbyś to zrobić ogólnie - tj. Użyć jednej wewnętrznej reprezentacji). Nie jestem ekspertem, ale przyszło mi to do głowy jako dobry, konkretny przykład.


0

reprezentacja kanoniczna oznacza wyświetlanie postaci w innym stylu, na przykład, jeśli napiszę literę A, oznacza to, że inna osoba może napisać literę A w innym stylu :)

Jest to zgodne z POLEM ROZPOZNAWANIA ZNAKÓW OPTYCZNYCH



0

Na pytania OP dotyczące formy kanonicznej i tego, w jaki sposób może poprawić wydajność equalsmetody, można odpowiedzieć, rozszerzając przykład przedstawiony w Effective Java.

Rozważ następującą klasę:

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

equalsSposób, w tym przykładzie w postaci dodatkowych kosztów korzystając String„s equalsIgnoreCasemetody. Jak wspomniano w tekście

możesz chcieć zapisać kanoniczną formę pola, aby metoda równości mogła wykonać tanie, dokładne porównanie form kanonicznych, zamiast bardziej kosztownego niestandardowego porównania.

Co Joshua Bloch ma na myśli, mówiąc o formie kanonicznej ? Cóż, myślę, że zwięzła odpowiedź Dónala jest bardzo odpowiednia. Możemy przechowywać Stringpole bazowe w CaseInsensitiveStringprzykładzie w standardowy sposób, być może w postaci wielkiej litery String. Teraz, można odwoływać się do tego kanoniczną formę z poniższych CaseInsensitiveString, jej wielką odmianę i wykonywać niskie oceny w swoim equalsand hashcodemetod.


0

Dane kanoniczne w RDBMS, dane graficzne;
Myśl jak „normalizacja” lub „normalna forma” danych w RDBMS. Te same dane istnieją w różnych tabelach, reprezentowane za pomocą unikalnego identyfikatora i mapowane w różnych tabelach.
lub
Pomyśl o pojedynczej formie danych w Graph Database, która jest reprezentowana w wielu trójek.

Główną zaletą tego rozwiązania jest zwiększenie wydajności Dml (manipulacja danymi), ponieważ można wstawić (wstawić / zaktualizować) tylko jedną wartość zamiast wielu.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.