وراثت

وراثت به یک کلاس اجازه می‌دهد که خصوصیات یا متدهایی را از کلاس دیگر به ارث برد. وراثت مانند رابطه پدر و پسری می‌ماند به طوریکه فرزند خصوصیاتی از قبیل قیافه و رفتار را از پدر خود به ارث برده باشد.

همه متد و خصوصیات کلاس پایه می‌توانند در کلاس مشتق مورد استفاده قرار بگیرند به استثنای اعضا و متدهای با سطح دسترسی private . همه کلاس‌ها در جاوا از کلاس Object ارث بری می‌کنند. مفهوم اصلی وراثت در مثال زیر نشان داده شده است :

  1: open class Parent
  2: {
  3:     fun showMessage()
  4:     {
  5:         println("Hello World!")
  6:     }
  7: }
  8: 
  9: class Child : Parent()
 10: 
 11: fun main(args: Array<String>)
 12: {
 13:     var child = Child()
 14:     child.showMessage()
 15: }
Hello World!

در این مثال دو کلاس با نامهای Parent و Child تعریف شده است. در خطوط 6-3 یک متد تعریف کرده ایم که با فراخوانی آن پیغام Hello World چاپ می شود. برای اینکه یک کلاس بتواند از این کلاس ارث بری کند باید قبل از کلمه کلیدی class کلمه open را بنویسید (خط 1). نحوه ارث بری یک کلاس به صورت زیر است :

class DerivedClass : BaseClass

براحتی می‌توان با قرار دادن علامت : بعد از نام کلاس و سپس نوشتن نام کلاسی که از آن ارث بری می‌شود (کلاس پایه) این کار را انجام داد. در خط 13 یک شیء از کلاس Child ایجاد کرده ایم. در خط 14 هم به راحتی می توانیم با گذاشتن علامت نقطه بعد از نام شیء متد ()showMessage کلاس پایه را فراخوانی کینم. وقتی از وراثت در کلاسها استفاده می‌کنیم، هم سازنده کلاس مشتق و هم سازنده کلاس پایه هر دو اجرا می‌شوند. اگر برای یک کلاس سازنده‌ای تعریف نکنیم کامپایلر به صورت خودکار یک سازنده برای آن ایجاد می‌کند. در وراثت کلاس ها، قوانینی بین سازنده های اولیه و ثانویه حاکم است که به آنها اشاره می کنیم. حالت اول این است که هر دو کلاس پدر و فرزند هیچ سازنده ای نداشته باشند. در این حالت، ارث بری بسیار راحت و به صورت زیر است :

open class Parent
class Child : Parent()

حالت دوم این است که کلاس پدر دارای سازنده اولیه باشد. در این صورت، هنگام ارث بری، در داخل پرانترهای آن باید آرگومانهایی به پارامترها اختصاص داده شود:

open class Parent(name: String)
class Child : Parent("Mike")

حالت سوم این است که هر دو کلاس دارای سازنده اولیه باشند و کلاس فرزند دارای سازنده ثانویه هم باشد. در این صورت باید بعد از سازنده ثانویه از کلمه this استفاده شود. در این حالت، در صورت استفاده از کلمه this، در اصل سازنده اولیه کلاس پدر فراخوانی می شود:

open class Parent(name: String)

class Child (name: String): Parent(name)
{
    constructor(name: String, family: String) : this(name)
}

و حالت چهارم این است که کلاس فرزند دارای سازنده اولیه نباشد. در این صورت کلاس باید از کلمه super بعد از سازنده ثانویه کلاس فرزند استفاده شود:

open class Parent(name: String)

class Child : Parent
{
    constructor(name: String, age: Int) : super(name)
}

در هنگام وراثت کلاس ها، ابتدا سازنده کلاس های والد و بعد سازنده کلاس های فرزند فراخوانی می شوند. به برنامه زیر توجه کنید:

  1: open class Parent
  2: {
  3:     init
  4:     {
  5:         println("Parent constructor was called!")
  6:     }
  7: }
  8: 
  9: open class Child : Parent()
 10: {
 11:     init
 12:     {
 13:         println("Child constructor was called!")
 14:     }
 15: }
 16: 
 17: class GrandChild : Child()
 18: {
 19:     init
 20:     {
 21:         println("GrandChild constructor was called!")
 22:     }
 23: }
 24: 
 25: fun main(args: Array<String>)
 26: {
 27:     GrandChild()
 28: }
Parent constructor was called!
Child constructor was called!
GrandChild constructor was called!

در برنامه بالا، کلاس GrandChild از کلاس Child و کلاس Child از کلاس Parent ارث بری کرده است. در نتیجه کلاس GrandChild دارای تمام خواص موجود در دو کلاس Child و Parent می باشد. زمانی که یک شیء از این کلاس ایجاد می کنیم (خط 27)، تمام کدهای موجود در بدنه دو کلاس Child و Parent و خود این کلاس اجرا می شوند.