Kotlin 8-Inheritance

Cenker Aydın
6 min readAug 15, 2023

--

Merhabalarrr! Umarım keyfiniz ve enerjiniz yerindedir. Bugün sizlerle OOP konseptinin olmazsa olmazlarından inheritance konusunu inceleyeceğiz. Bütün seriye buradan erişebilirsiniz. Beğenmeyi ve takip etmeyi unutmayın. Keyifli Okumalar!

Inheritance

Kotlin, nesne yönelimli proglama (OOP) konseptlerine sahip bir programlama dilidir. OOP kodu nesnelere ve sınıflara dayalı olarak organize etme yeteneğine sahiptir. Kotlin’de sınıf mirası (inheritance) da bu OOP prensiplerinden biridir. Sınıf mirası, bir sınıfın diğer bir sınıftan özelliklerini ve davranışlarını alabilmesini sağlar.

Kotlin’de sınıf mirası oluşturmak için open ve override anahtar kelimeleri kullanılır. open, bir sınıfın veya sınıf üyenin miras alınabilir (override edilebilir) olduğunu belirtir. override ise miras alınmış bir sınıf üyesinin (metod veya özellik) child classta farklı bir işlevde kullanılması.

Kotlin’de, sınıf mirası kullanırken override anahtar kelimesi ile ilgili bazı kurallar bulunmaktadır. Bu kurallar, miras alınan sınıfın üyelerini nasıl override edebileceğimizi ve hangi durumlarda kullanabileceğimizi belirtir. İşte override anahtar kelimesinin kuralları:

  1. Üst Sınıf (Superclass, Base Class, Parent Class) Üyeleri:

Yazı boyunca Miras veren class için Parent Class kavramını kullanacağım, farklı yerlerde üstte gördüğünüz gibi farklı isimlerle adlandırılabilir.

  • Bir üst sınıfın fonksiyonları, özellikleri veya başka üyeleri sadece open veya abstract olarak işaretlenmişse override edilebilir.
  • Bir üst sınıfın private, final veya public olarak işaretlenmiş üyeleri override edilemez.

2. Alt Sınıf (Subclass, Child Class, Derived Class) Üyeleri:

Yazı boyunca Miras alan class Child class kavramını kullanacağım, farklı yerlerde üstte gördüğünüz gibi farklı isimlerle adlandırılabilir.

  • Bir child class, parent class’ın aynı isimli ve imzada (parametre listesi ve dönüş tipi) olan bir fonksiyonunu override etmek istediğinde, override anahtar kelimesi kullanılmalıdır.
  • Bir child class’ın override ettiği bir üye, erişim belirleyicisinin (access modifier) görünürlük düzeyini aşağı yönde değiştirebilir (genişletebilir), ancak daraltamaz.
  • Child class’ın override ettiği bir üye, imza (parametre listesi ve dönüş tipi) konusunda da aynı olmalıdır.

Kotlin’de bütün classlar default olarak final tanımlanırlar. Bu yüzden bir classı direkt olarak miras alamayız. Bir sınıfı miras almak istiyorsanız sınıfın başına openkeywordunu getirmeniz gerekmektedir ve bir sınıf başka bir sınıfı miras alırken : (iki nokta) kullanılması gerekmektedir.

Görselde görüldüğü gibi open yani inherit alınabilir Car1 classı, düz Car2 classı ve bunları inherit eden Model ve Model1 classlarını oluşturduk. Car1 classı open olduğu için Model classı tarafından rahatlıkla miras alınabilir ama Car2 classı default olarak final olarak tanımlandığı için görüldüğü gibi uyarı verecektir.

final classın neden inherit alınamadığı hatası

Üst Sınıf (Parent Class) ve Alt Sınıf (Child Class) İlişkisi:

Bu kavramları bir örnek üzerinden daha anlaşılır bir şekilde inceleyelim.

open class Canli(var name: String, var age: Int) {
open fun selamla() {
println("Merhaba, ben bir canlıyım.")
}
}

class Insan(name: String, yas: Int) : Canli(ad, yas) {
override fun selamla() {
println("Merhaba, ben insanım. Yaşım: $age")
}
}

Bu kod örneği aslında inheritance konusunu anlamak için çok uygun, anlaşılabilir ve basit bir örnek. Gelin anlatayım:

Canli adında open bir parent class oluşturduk, parent class olmasının nedeni Insan classı tarafından inherit alınıyor olması ve içerisinde selamla adında open bir fonksiyon oluşturduk, bundan sonra Insan adında bir child class oluşturduk, child class olmasının nedeni Canli classını miras alması ve Canli classındaki selamla fonksiyonunu override ederek kullandık.

Super Anahtar Kelimesi

super anahtar kelimesi ve super() fonksiyonu, Kotlin'deki sınıf mirası (inheritance) ilişkisinde kullanılan önemli kavramlardır. Bir child class, parent class’ın özelliklerini ve davranışlarını miras alırken, super anahtar kelimesi ve super() fonksiyonu, alt sınıfta üst sınıfa ait constructor ve metotları çağırmak için kullanılır.

  1. super Anahtar Kelimesi:

super anahtar kelimesi, alt sınıf içinde üst sınıfa ait metotları veya özellikleri çağırmak için kullanılır. Bu, alt sınıfın kendi override edilmemiş üst sınıf metotlarına erişmesine olanak tanır.

open class ParentClass{
open fun selamVer() {
println("Merhaba, ben super classım.")
}
}

class ChildClass: ParentClass(){
override fun selamVer() {
super.selamVer() // Üst sınıfın selamVer() metodu çağrılıyor
println("Merhaba, ben sub classım.")
}
}

fun main(){
var sub=SubClass()
sub.selamVer()
}

main fonksiyonunda ChildClass’ın nesnesini oluşturup, selamVer fonksiyonunu çağırdığımızda çıktımız şöyle olacaktır:

super fonksiyonuyla SuperClassın fonksiyonunu çağırdığımız için önce o, sonra SubClassın selamVer fonksiyonu çağırılacak.

Overload

Overload: Aynı isme sahip ancak farklı parametre listelerine sahip metotların aynı sınıf veya sınıf hiyerarşisi içinde tanımlanabilmesine denir.

Parent classların sahip olduğu yetkinlikleri child classlarda değiştirerek kullanmak istediğiniz zaman kullanabilirsiniz.

open class SuperClass{
open fun selamVer() {
println("Merhaba, ben super classım.")
}
}

class SubClass: SuperClass() {
override fun selamVer() {
super.selamVer() // Üst sınıfın selamVer() metodu çağrılıyor
println("Merhaba, ben sub classım.")
}
//Overloading
fun selamVer(name: String){
println("Merhaba, benim adım $name")
}
}

Override ve Overload kavramlarını tek bir örnek üzerinde inceleyerek arasındaki farkları gördük.

Kotlin inheritance primary constructor:

Eğer Child Class primary constructor’a sahipse, child class’ın, parent class’ın constructor’ını çağırırken parent class’ın constructoru için gerekli parametreleri child classın parametreleriyle uyumlu hale getirmeliyiz.

Bu cümleden hiçbir şey anlamamış olabilirsiniz, bir örnek ile açıklayayım.

//Parent Class
open class Employee(name: String,age: Int) {
init{
println("Name of the Employee is $name")
println("Age of the Employee is $age")
}
}
//Child class
class CEO( name: String, age: Int, salary: Double): Employee(name,age) {
init {
println("Salary $salary euro")
}
}
fun main() {
CEO("Cenker Aydın", 21, 450.00)
}
Output

Employee classında 2 tane parametre alan primary const. oluşturduk ve init bloğuyla çalıştırıyoruz. Eğer init bloğu, primary const. falan ne diyorsanız sizi şuraya alalım :) Okuyup geldiğinizi düşünerek devam ediyorum. CEO classında da 3 tane parametre alan primary const. oluşturduk ve 2 tanesi Employee ile aynı parametreleri içeriyor, o yüzden : Employee classını inherit alırken parametreleri de uyumlu hale getirmek için Employee(name, age) ifadesini kullandık.

Kotlin inheritance secondary constructor:

Eğer child class primary const. içermiyorsa, child classın secondary constructor’ından parent classın secondary constructorını çağırmak için super anahtar kelimesini kullanmanız gerekmektedir. Aynı zamanda child classın secondary constructorunu, child classın parametreleri ile başlatmanız gerekmektedir.

Bir örnek ile daha anlaşılır hale getirelim:

//Parent Class
open class Employee {
constructor(name: String,age: Int){
println("Name of the Employee is $name")
println("Age of the Employee is $age")
}
}
//Child Class
class CEO : Employee{
constructor( name: String,age: Int, salary: Double): super(name,age) {
println("Salary $salary euro")
}
}
fun main() {
CEO("Cenker Aydın ", 21, 450.00)
}
Output

Kısaca Parent Classın secondary const., Child class’ın secondary const. kullanırken çağırmak için super anahtar kelimesini kullanmanız gerekiyor.

Overriding Member properties:

Yukarıdaki örneklerde parent class içerisindeki fonksiyonu nasıl child classta override edebileceğinizi göstermiştim, şimdi parent class içerisindeki bir değişkeni nasıl override edebileceğinizi göstereceğim.

// Parent Class
open class Animal {
open var name: String = "Dog"
open var speed = "40 km/hr"

}
// Child Class
class Tiger: Animal() {
override var name = "Tiger"
override var speed = "100 km/hr"
}
fun main() {
val t = Tiger()
println(t.name+" can run at speed "+t.speed)
}

Output: Tiger can run at speed 100 km/hr

Gördüğünüz gibi değişkeni child classta değiştirmek istediğiniz yeni değişken oluşturmak yerine parent classtaki değişkeni override ederek değiştirebilirsiniz.

Inheritance avantajlarından bahsederek yazımızı tamamlayalım:

  1. Kodun Tekrar Kullanımı: Kalıtım, mevcut bir sınıfın özelliklerini ve metodlarını yeni bir sınıfa aktardığı için kodun tekrar kullanımını sağlar. Bu, aynı veya benzer özelliklere sahip sınıflar arasında kodun yeniden yazılmasını önler.
  2. Kodun Daha Organize Olması: Kalıtım sayesinde, benzer sınıfları bir arada gruplayabilir ve daha iyi organize edebilirsiniz. Ortak özellikleri olan sınıfları bir temel sınıf (üst sınıf) altında toplayarak, kodun daha anlaşılır ve düzenli olmasını sağlayabilirsiniz.
  3. Miras Alınan Davranışları Genişletme ve Değiştirme: Kalıtım, miras alınan sınıfın davranışlarını genişletebilmenizi veya değiştirmenizi sağlar. Alt sınıflar, üst sınıfın metodlarını ve özelliklerini korurken, bu metodları gerektiğinde yeniden tanımlayarak özelleştirebilirler.
  4. Kodun Bakımı ve Güncellemesi: Kalıtım, kodun bakımını ve güncellemesini kolaylaştırır. Özellikle üst sınıfta yapılan bir değişiklik, miras alan tüm alt sınıflara otomatik olarak yansır. Bu da kodun güncel tutulmasını ve tutarlılığını sağlar.
  5. Polimorfizm Desteği: Kalıtım, polimorfizm konseptine olanak tanır. Bu, farklı alt sınıfların aynı adı taşıyan ancak farklı davranışlara sahip metodları olabileceği anlamına gelir. Polimorfizm, programın daha esnek ve genişletilebilir olmasını sağlar.
  6. Kodun Daha Az Hata İçermesi: Kalıtım, kodun daha az hata içermesine yardımcı olabilir. Çünkü kodun tekrar kullanılması sayesinde aynı hataların tekrar tekrar yapılma riski azalır.

Kotlin’de inheritance konusunu işledik, umarım keyif almışssınızdır. Bir sonraki yazılarda görüşmek üzere!

Bana ulaşmak için Linkedin , Github

--

--