JavaProgramlamaKıdemli Java Geliştirici

**Enum** sınıfının **compareTo** metodunun yalnızca aynı belirli enumeration alt türlerinin argümanlarını kabul etmesini sağlamak için hangi özyinelemeli tür sınırı bildirimi kullanılır?

Hintsage yapay zeka asistanı ile mülakatları geçin

Sorunun yanıtı

Enum sınıfı Enum<E extends Enum<E>> olarak bildirilmiştir, bu da F-sınırlandırılmış çok biçimlilik (veya özyinelemeli tür sınırı) olarak bilinir. Bu bildirim, tür parametresi E'yi kendisi tarafından parametreleştirilmiş bir Enum alt sınıfı olma şartıyla kısıtlar ve böylece her somut enum türünü (örneğin DayOfWeek) kendi sınıf literali ile bağlar. Bu tasarım, compareTo metodunun parametresini ham Enum yerine tür E olarak bildirmesine olanak tanır ve derleme zamanında bir DayOfWeek'in yalnızca başka bir DayOfWeek ile karşılaştırılabileceğini garanti eder; bu, Thread.State gibi alakasız bir enum ile karşılaştırma yapmasının önüne geçer. Sonuç olarak, derleyici, çalışma zamanı instanceof kontrollerine veya tür dönüştürmelerine ihtiyaç duymadan türler arası sıralama karşılaştırmalarını engeller ve hem tür güvenliğini hem de sıradaki sıralama performansını korur.

Hayattan bir durum

Bir geliştirme ekibi, temel yöntemlerin where() ve limit() gibi belirli alt sınıf türünü döndürmesi gereken, bir veri erişim katmanı için akıcı bir QueryBuilder API'si tasarlamak zorunda kaldı, böylece türemiş yapıcılar olan SqlQueryBuilder veya GraphQlQueryBuilder içinde yöntem zincirlemesine olanak tanınmış oldu.

Çözüm 1: Açık geçersiz kılma ile değişken dönüş türleri.

Her alt sınıf, akıcı yöntemi her zaman kendi özel dönüş türünü bildirmek için geçersiz kılabilir. Bu, derleme zamanı güvenliği sağlar, ancak her alt sınıfta temel API geliştiğinde zorunlu kod yazma yükü yaratır ve miras alma hiyerarşisi boyunca DRY ilkesini ihlal eder.

Çözüm 2: Kontrolsüz tür dönüşümleri ile ham tür dönüşleri.

Temel sınıf, ham QueryBuilder türünü döndürebilir ve bu da alt sınıfların this'i kendi özel türlerine dönüştürmeye zorlar. Bu yaklaşım, kod yazma yükünü ortadan kaldırır, ancak derleyici uyarıları üretir ve miras yapısı karmaşık hale gelirse çalışma zamanında ClassCastException riski taşır ve temel olarak tür güvenliğini ihlal eder.

Çözüm 3: F-sınırlandırılmış çok biçimlilik.

Ekip, temel sınıfı abstract class QueryBuilder<T extends QueryBuilder<T>> olarak bildirdi ve akıcı yöntemler T'yi döndürdü. Alt sınıflar kendilerini class SqlQueryBuilder extends QueryBuilder<SqlQueryBuilder> olarak tanımladı. Bu teknik, Enum'la aynı özyinelemeli sınır desenini kullanarak, derleyicinin where()'nin tam olarak SqlQueryBuilder döndürmesini zorunlu kılmasını sağladı ve herhangi bir tür dönüştürmesi veya yöntem çoğaltması gerektirmedi.

Ekip, Çözüm 3'ü seçti çünkü bu, kod çoğaltımını ortadan kaldırırken tüm miras zinciri boyunca katı tür güvenliğini korudu. Ortaya çıkan DSL, genel işlemlerden sonra alt sınıfa özel yöntemleri doğru bir şekilde önererek otomatik tamamlama sağladı ve API'nın benimsenme aşamasında entegrasyon hatalarını %40 oranında azalttı.

Adayların genellikle gözden kaçırdığı noktalar

Soru 1: Neden Enum<E extends Enum<E>> bildirimi sadece Enum<E> yerine gereklidir?

Sadece Enum<E> bildirimi yapmak, herhangi bir rastgele türün parametre olarak geçmesine izin verir, yalnızca belirli enum türleri değil. Özyinelemeli sınır E extends Enum<E>, E'yi kendisi ile başlatılmış bir somut enum sınıfı olma zorunluluğu getirir. Bu kendine referans veren kısıtlama, compareTo(E o) gibi yöntemlerin yalnızca tam olarak aynı enum alt türünü kabul etmesini sağlar; bu, çapraz tür karşılaştırmalarını çalışma zamanı ClassCastException'ına ertelemek yerine derleme zamanında önler. Bu sınır olmadan, Comparable uygulaması, ham Enum veya Object'i kabul etmek zorunda kalır ve bu da EnumSet ile EnumMap uygulamalarının verimli olmasını sağlayan tür kesinliğini kaybeder.

Soru 2: F-sınırlandırılmış çok biçimlilik, enum sabitlerini almak için yansıma ile nasıl etkileşir?

Bir enum sınıfı üzerinde getEnumConstants() yöntemini yansıma kullanarak çağırdığınızda, özyinelemeli sınır geri dönen dizinin E[] türünde olmasını sağladığından, ham bir nesne dizisi olarak değil. Bu, Enum yapıcısının getDeclaringClass() üzerinden Class<E> nesnesini yakalamasına bağlıdır; bu, tür parametresinin doğru bir şekilde belirli alt sınıfa bağlı olmasını gerektirir. Adaylar genellikle bu bağlamanın, derleyicinin sınır tür bilgisi aracılığıyla derleme zamanında kesin bir sabit kümesinin bilindiği için enum'lar üzerindeki switch ifadelerini tableswitch bayt kodu talimatı kullanarak optimize etmesine olanak tanıdığını gözden kaçırır; bu da daha yavaş olan lookupswitch'ten kaçınmayı sağlar.

Soru 3: Özyinelemeli tür sınırları, genel dizi oluşturma sırasında heap kirlenmesine yol açabilir mi ve Enum bunu nasıl önler?

Sınır kendisi tür güvenli olsa da, adaylar genellikle tür parametrelerinin dizilerini oluşturma girişiminde sıkıntı yaşar (örneğin, new E[10]). Bu, tür silinmesi nedeniyle yasaktır. Ancak, Enum sınıfı bu kısıtlamayı derleyici sihiri ile aşar: derleyici, her enum için E[] döndüren sentetik statik bir values() yöntemi oluşturur ve belirli enum'un Class türünden elde edilen sınıf belirteci ile java.lang.reflect.Array.newInstance() kullanarak diziyi oluşturur. Bu, döndürülen dizinin doğru yeniden yapılandırılmış bileşen türüne sahip olmasını sağlar ve ClassCastException veya heap kirlenmesine yol açmadan çalışır; bu, manuel genel sınıfların yansıma olmadan kolayca tekrarlayamadığı bir tekniktir.