Java'daki "kanonik form" veya "kanonik temsil" terimi ne anlama geliyor?


91

Bu terimin kullanıldığını sık sık duydum, ancak onu hiçbir zaman gerçekten anlamadım.

Bu ne anlama geliyor ve herhangi biri bazı örnekler verebilir / beni bazı bağlantılara yönlendirebilir mi?

DÜZENLEME: Cevaplar için herkese teşekkürler. Ayrıca, Effective Java'da belirtildiği gibi, kanonik temsilin equals () performansında nasıl yararlı olduğunu söyleyebilir misiniz?

Yanıtlar:


58

Wikipedia, Kanonikleştirme terimine işaret ediyor .

Birden fazla olası gösterime sahip verileri "standart" bir kanonik gösterime dönüştürmek için bir işlem. Bu, eşdeğerlik için farklı temsilleri karşılaştırmak, farklı veri yapılarının sayısını saymak, tekrarlanan hesaplamaları ortadan kaldırarak çeşitli algoritmaların verimliliğini artırmak veya anlamlı bir sıralama düzeni empoze etmeyi mümkün kılmak için yapılabilir.

Unicode örneği benim için en mantıklı:

Unicode standardındaki değişken uzunluklu kodlamalar, özellikle UTF-8, en yaygın karakterler için birden fazla olası kodlamaya sahiptir. Bu, her bir dize karakterinin olası her kodlamasının dikkate alınması gerektiğinden, dize doğrulamasını daha karmaşık hale getirir. Tüm karakter kodlamalarını dikkate almayan bir yazılım uygulaması, uygulama tasarımında geçersiz sayılan dizeleri kabul etme riskini taşır ve bu da hatalara veya saldırılara neden olabilir. Çözüm, her karakter için tek bir kodlamaya izin vermektir. Kanonikleştirme, her dize karakterini izin verilen tek kodlamaya çevirme işlemidir. Bir alternatif, yazılımın bir dizenin standartlaştırılmış olup olmadığını belirlemesi ve yoksa onu reddetmesidir. Bu durumda, bir istemci / sunucu bağlamında, standartlaştırma müşterinin sorumluluğunda olacaktır.

Özetle, veriler için standart bir temsil biçimi. Bu formdan daha sonra ihtiyacınız olabilecek herhangi bir temsile dönüştürebilirsiniz.


64

Kanonik'in iki ilişkili kullanımı olduğuna inanıyorum: formlar ve örnekler.

Bir standart bir şekilde kaynağın belirli bir türdeki değerleri, tarif edilen ya da birden fazla şekilde temsil edilir ve bu yollardan Tercih edilen bir standart form olarak seçilir edilebileceği anlamına gelir. (Bu form, İncil'e giren kitaplar gibi kanonlaştırılmıştır ve diğer formlar değildir.) Kanonik bir formun klasik bir örneği, tek bir dosyaya çeşitli şekillerde başvurulabilen hiyerarşik bir dosya sistemindeki yollardır. :

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

Bu dosyanın kanonik temsilinin klasik tanımı son yoldur. Yerel veya göreceli yollarla, bağlamsal bilgi olmadan kaynağı global olarak tanımlayamazsınız. Mutlak yollarla kaynağı tanımlayabilirsiniz, ancak iki yolun aynı varlığa başvurduğunu söyleyemezsiniz. Kanonik formlarına dönüştürülen iki veya daha fazla yolla, yukarıdakilerin hepsini yapabilir, ayrıca iki kaynağın aynı olup olmadığını belirleyebilir, bunun uygulamanız için önemli olup olmadığını belirleyebilirsiniz ( takma ad sorununu çözün ).

Bir kaynağın kanonik biçiminin, o belirli biçimin kendisinin bir kalitesi olmadığını unutmayın; dosya yolları gibi belirli bir tür için birden fazla olası kanonik form olabilir (örneğin, sözlükbilimsel olarak önce tüm olası mutlak yollar). Bir form, belirli bir uygulama nedeni için kanonik form olarak veya belki de keyfi olarak herkes aynı dili konuşacak şekilde seçilir.

Nesneleri kanonik örneklerine zorlamak aynı temel fikirdir, ancak bir kaynağın "en iyi" temsilini belirlemek yerine, rasgele bir örnek sınıfının bir örneğini kanonik referansla aynı "içeriğe" sahip bir örneğini seçer ve ardından tüm referansları dönüştürür bir kanonik örneği kullanmak için eşdeğer nesnelere.

Bu, hem zamanı hem de mekanı optimize etmek için bir teknik olarak kullanılabilir. Bir uygulamada eşdeğer nesnelerin birden çok örneği varsa, hepsini belirli bir değerin tek kanonik örneği olarak çözülmeye zorlayarak, her bir değerden biri hariç tümünü ortadan kaldırabilir ve artık karşılaştırabileceğiniz için yerden ve muhtemelen zamandan tasarruf edebilirsiniz. nesne eşdeğerliğine ( equals()yöntem) karşılık referans kimliğine (==) sahip bu değerler .

Standart örneklerle performansı optimize etmenin klasik bir örneği, aynı içeriğe sahip dizeleri daraltmaktır. Arayan String.intern()aynı karakter dizisi ile iki dizeleri o metinde aynı kanonik String nesnesi geri garantilidir. Tüm dizelerinizi bu kurallılaştırıcıdan geçirirseniz, eşdeğer dizelerin aslında aynı nesne başvuruları olduğunu bilirsiniz, yani takma adlar

Java 5.0+ sürümündeki enum türleri, belirli bir enum değerinin tüm örneklerini, değer serileştirilmiş ve serileştirilmemiş hale getirilmiş olsa bile bir VM içinde aynı kanonik örneği kullanmaya zorlar. Bu nedenle javada enum türü if (day == Days.SUNDAY)ise cezasız olarak kullanabilirsiniz Days. Bunu kendi dersleriniz için yapmak kesinlikle mümkündür, ancak dikkatli olun. Ayrıntılar ve tavsiye için Effective Java by Josh Bloch'u okuyun .


32

"Standart biçim / gösterimi" anlamak için iyi bir örnek, "boole" nin XML şeması veri türü tanımına bakmaktır:

  • Boole'nin "sözcüksel temsili" şunlardan biri olabilir: {true, false, 1, 0}oysa
  • "kanonik temsil" yalnızca biri olabilir {true, false}

Bu, özünde şu anlama gelir:

  • "true"ve "1"standart repr ile eşleştirilir. "true"ve
  • "false"ve "0"kanonik repr ile eşleştirilir."false"

bkz boolean için w3 XML şeması veri türü tanımı


28

"Kanonik" kelimesi "standart" veya "normal" ile eşanlamlıdır. Java'ya özgü bir anlamı yoktur.


3
canonical, standart veya normal IMO'dan daha zengin bir anlama sahiptir.
squid

21

genelliği kaybetmeden en basit ve en önemli biçime indirgenmiş


5

Bunu hatırlamanın kolay bir yolu, "kanonik" in teolojik çevrelerde kullanılma şeklidir, kanonik gerçek gerçek gerçektir, bu yüzden iki kişi onu bulursa aynı gerçeği bulmuşlardır. Kanonik örnekle aynı. Eğer ikisini bulduğunuzu düşünüyorsanız (yani a.equals(b)) gerçekten sadece bir tane (yani a == b) var. Dolayısıyla eşitlik, kanonik nesne durumunda özdeşliği ifade eder.

Şimdi karşılaştırma için. Artık a==b veya kullanma seçeneğiniz var, a.equals(b)kanonik örnek durumunda aynı cevabı üretecekleri için, ancak a == b referansın karşılaştırmasıdır (JVM, iki sayıyı son derece hızlı bir şekilde karşılaştırabilir, çünkü bunlar yalnızca iki 32 bitlik modeldir) buna a.equals(b)bir yöntem çağrısı ve daha fazla ek yük içerir.


2

Başka bir iyi örnek de şunlar olabilir: kartezyen (x, y, z), küresel (r, teta, phi) ve silindirik koordinatların (r, phi, z) kullanımını destekleyen bir sınıfınız var. Eşitliği sağlamak için (eşittir yöntemi), muhtemelen tüm gösterimleri, seçtiğiniz bir "kanonik" temsiline, örneğin küresel koordinatlara dönüştürmek isteyeceksiniz. (Ya da belki bunu genel olarak yapmak istersiniz - yani bir iç temsil kullanın.) Ben bir uzman değilim, ancak bu bana belki iyi bir somut örnek olarak geldi.


0

kanonik temsil, karakteri farklı bir tarzda görüntülemek anlamına gelir, örneğin bir harf yazarsam, başka bir kişinin A harfini farklı bir tarzda yazabileceği anlamına gelir :)

Bu, OPTİK KARAKTER TANIMA ALANINA göredir



0

OP'nin kanonik biçime ve equalsyöntemin performansını nasıl geliştirebileceğine ilişkin soruları, Etkili Java'da verilen örneği genişleterek yanıtlanabilir.

Aşağıdaki sınıfı düşünün:

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

equalsBu örnekte, yöntem kullanarak maliyet eklemiştir String'in equalsIgnoreCaseyöntemi. Metinde bahsedildiği gibi

Eşittir yönteminin, daha maliyetli standart olmayan bir karşılaştırma yerine kurallı biçimler üzerinde ucuz ve tam bir karşılaştırma yapabilmesi için alanın kurallı bir biçimini depolamak isteyebilirsiniz.

Joshua Bloch, kanonik form derken ne demek istiyor ? Bence Dónal'ın kısa cevabı çok uygun. Örnekteki temel Stringalanı standart bir şekilde saklayabiliriz , belki de . Şimdi, bu referans verebilir kanonik formu ait , onun büyük varyant, ve ucuz değerlendirmeler gerçekleştirmek ve yöntemlerle.CaseInsensitiveStringStringCaseInsensitiveStringequalshashcode


0

RDBMS'de Kanonik Veriler, Grafik Verileri;
RDBMS'deki verilerin "Normalleştirilmesi" veya "Normal formu" olarak düşünün. Aynı veriler, benzersiz bir tanımlayıcıyla temsil edilen ve farklı tablolarda eşlenen farklı tablolarda bulunur.
veya
Grafik Veritabanında birçok üçlü olarak temsil edilen tek bir veri formunu düşünün.

Bunun en büyük yararı, Dml'yi (Veri işleme) daha verimli hale getirmektir, çünkü birçok değer yerine yalnızca bir değeri yükseltebilirsiniz (ekleme / güncelleme).

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.