ProgramlamaKotlin Geliştirici

Kotlin'de init blokları ve 'super' anahtar kelimesinin kullanımı ile nesne başlatma mekanizmasını tanımlayın. Başlatma sırası Java'dan nasıl farklıdır, kalıtım hiyerarşisi ve yapıcı çağrılarla ilgili hangi nüanslar vardır?

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

Cevap.

Init blokları ve Kotlin'deki super çağrısı, nesnelerin doğru bir şekilde başlatılmasını sağlamak için sınıf hiyerarşisini dikkate alır. Bu, yapılar ve kalıtım üzerindeki temel mekanizmalardır.

Sorunun Tarihi

Java'da yapıcılar, super(...) ile açıkça veya varsayılan olarak dolaylı yoldan çağrılabilir. Kotlin'de durum tamamen farklıdır: birincil ve ikincil yapıcılar arasında kesin bir ayrım vardır ve init bloğu, başlatma için kullanılır.

Problem

Ana zorluk, özelliklerin ne zaman başlatıldığını, init bloklarının ne zaman çağrıldığını ve özellikle sınıfların kalıtımı ve birincil/ikincil yapıcıların kombinasyonu söz konusu olduğunda yapıcı çağrı sırasının nasıl kurulduğunu doğru bir şekilde anlamaktır.

Çözüm

  • Kotlin'de önce tüm ikincil yapıcıların birincil yapıcıya delegasyonu gerçekleştirilir, ardından süper sınıfın yapıcı çağrılır ve daha sonra init blokları işlenir;
  • Süper sınıfa parametre geçirmek için bunları yapıcının içinde açıkça belirtmek gerekir;
  • Dış sınıfın gövdesinde tanımlanan özelliklerin, init bloğu çalışmadan önce başlatıldığını unutmamak önemlidir.

Kod örneği:

open class Base(val name: String) { init { println("Base init: $name") } } class Derived(name: String, val age: Int): Base(name) { init { println("Derived init: $name, $age") } } fun main() { Derived("Ivan", 25) } // Çıktı: // Base init: Ivan // Derived init: Ivan, 25

Anahtar özellikler:

  • Dış sınıfın tüm özellikleri, init bloğu çalışmadan önce başlatılır;
  • Öncelikle süper sınıfın yapıcısı çağrılır;
  • İkincil yapıcı, ya doğrudan ya da bir zincir aracılığıyla birincil yapıcıyı çağırmak zorundadır.

Kandırıcı Sorular.

Kalıtım zincirinde init blokları hangi sırayla çalıştırılır?

Öncelikle süper sınıfın init blokları, onun özelliklerinin başlatılmasının ardından çalıştırılır, ardından alt sınıfın init blokları, kendi özelliklerinden sonra çalışır.

Kod örneği:

open class A { init { println("A") } } class B: A() { init { println("B") } } fun main() { B() } // A -> B

Kotlin'de super() yapıcı dışında çağrılabilir mi?

Hayır, süper sınıf çağrısı yalnızca yapıcı tanımının bir parçası olarak yapılır ve süper yapıcıya parametre sağlar.

Kotlin'de ikincil yapıcı, birincil yapıcıyı çağırmaktan kaçınabilir mi?

Hayır, tüm ikincil yapıcılar ya başka bir ikincil yapıcıya ya da birincil yapıcıya delegasyon yapmak zorundadır. Birincil yapıcı, süper yapıcıyı da çağırmaktadır.

Yaygın Hatalar ve Antipattern'ler

  • Süper yapıcı çağrılmadan önce hesaplanan bir özellik tanımlamak hata verebilir;
  • Başlatılmamış özellikleri kullanmaya çalışırken başlatma sırasındaki hatalar;
  • İkincil yapıcılarda dairesel bağımlılıklar.

Gerçek Hayattan Örnek

Negatif Durum

Geliştirici, süper sınıfın init blokunda alt sınıfta başlatılan bir özelliğe erişmeye çalışıyor:

open class A { init { println(f()) } open fun f() = "A" } class B : A() { private val s = "B" override fun f() = s }``` **Artılar:** - Polimorfizm kullanımı. **Eksikler:** - Özellik s henüz başlatılmamış, süper sınıfın init çağrısı sırasında - sonuç null veya hata. ## Pozitif Durum Başlatmayı, yapıcıdan yeniden tanımlanabilir yöntemler veya özellikleri çağırmamayı sağlayacak şekilde organize etme: ```kotlin open class A { init { println("init A") } open fun f() = "A" } class B : A() { private val s = "B" override fun f() = s init { println(f()) } }``` **Artılar:** - Başlatılmamış verilere yönlendirme yok; - Başlatma sırası garanti altına alınmıştır. **Eksikler:** - Doğru başlatma için kod miktarı artmaktadır.