مقالات باگتو

کلاس ها و وراثت در زبان کاتلین
کلاس ها و وراثت در زبان کاتلین

در ادامه آموزش های کاتلین در اندروید  به آموزش کلاس و وراثت در کاتلین می رسیم که در این مقاله قصد داریم اون رو بصورت کامل برای شما بیان کنیم.

کلاس های کاتلین با استفاده ازکلمه کلیدیclassنوشته میشوند.

class Invoice {
}

تعریف کلاس شامل کلمهclassو اسمی که برای کلاس مینویسیم (مشخص کردن نوع پارامترهای آن ، سازنده اولیه و غیره) و بدنه کلاس است. headerو بدنه هم اختیاری است. اگر کلاس بدنه نداشته باشد {} ها را میتوان ننوشت.

class Empty

 

Constructors( سازنده)

یک کلاس در کاتلین می تواند یک سازنده اصلی و یک یا چند سازنده ثانویه داشته باشد.سازنده اصلی بخشی ازheaderکلاس است  و بعد از آن نام کلاس (و نوع پارامترهای آن که اختیاری هستند) نوشته میشود.

class Invoice constructor(firstName: String){
    
}

اگر سازنده اصلی هیچگونه انوتیشن  یاmodifiresنداشته باشد، کلمه کلیدیconstructor را میتوان ننوشت.


class Invoice (firstName: String){

}

سازنده اصلی میتواند کدی را نداشته باشد. کد اولیه را می توان در بلاک هایی نوشت که در اول کلاس قرار میگیرند که با کلمه کلیدیinitنوشته میشوند.

در طی یک نمونه سازی اولیه، بلاک هایinit  به همان ترتیب که در بدنه کلاس تعریف شده اند اجرا میشوند.

class Invoice (firstName: String){
        val firstProperty = "First property: $firstName".also(::println)

        init {
            println("First initializer block that prints ${firstName}")
        }

        val secondProperty = "Second property: ${firstName.length}".also(::println)

        init {
            println("Second initializer block that prints ${firstName.length}")
        }
}

توجه داشته باشید که پارامترهای سازنده اولیه در بلاک های اولیه قابل استفاده است. زمانی که در سازنده اولیه کلاس پارامتر هایی را دریافت می کنیم باید قبل از آنها مانند تعریف متغیر های معمولیvar  قابل تغییر یاval غیر قابل تغییر بزاریم.

class Invoice (val firstName: String, val lastName: String, var age: Int) {
}

اگر سازنده دارای انوتیشن یاmodifierباشد، کلید واژهconstructorمورد نیاز است وmodifierها قبل از آن نوشته میشوند.

class Invoice public @Inject constructor(name: String) {
}

سازندگان ثانویه (Secondary constructors)

این کلاس همچنین می تواند سازنده های ثانویه را معرفی کند ، که با سازنده پیشوند هستند.

class Invoice {
    var children: MutableList<Invoice> = mutableListOf<Invoice>();
    constructor(parent: Invoice) {
        parent.children.add(this)
    }
}

 

اگر کلاس دارای یک سازنده اولیه باشد، هر سازنده ثانویه باید به سازنده اولیه اعم از مستقیم یا غیر مستقیم از طریق سازنده های ثانویه دیگری واگذار شود.

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

class Invoice (val name: String) {
    var children: MutableList<Invoice> = mutableListOf<Invoice>();
    constructor(name: String, parent: Invoice) : this(name) {
        parent.children.add(this)
    }
}

توجه داشته باشید كه كد موجود در بلاک های اولیه سازنده به طور مؤثر جزئی از سازنده اصلی می شود. فراخوانی سازنده اصلی به عنوان اولین عبارت از سازنده ثانویه اتفاق می افتد، بنابراین کد در کلیه بلاک های اولیه و آغازگرهای خاص قبل از بدنه سازنده ثانویه انجام می شود. حتی اگر کلاس سازنده اصلی نداشته باشد فراخوانی سازنده هنوز به طور ضمنی اتفاق می افتد، و بلاک های اولیه هنوز اجرا می شوند.

class Invoice{
    init {
        println("Init block")
    }

    constructor(i: Int) {
        println("Constructor")
    }
}

 

اگر یک کلاس غیر انتزاعی(non-abstract) هیچ سازنده (اولیه یا ثانویه) را اعلام نکند، یک سازنده اولیه بدون هیچ آرگومانی خواهد داشت. کلاس سازنده عمومی خواهد بود. اگر نمی خواهید کلاس شما دارای یک سازنده عمومی باشد، باید یک سازنده اولیه خالی با خصوصی بنویسید.

class Invoice private constructor () {/*...*/ }

توجه: درJVM، اگر تمام پارامترهای سازنده اولیه دارای مقادیر پیش فرض باشند، کامپایلریك سازنده با پارامتر اضافی تولید می كند كه از مقادیر پیش فرض استفاده می كند. این امر استفاده از کاتلینرا با كتابخانه هایی مانندjacksonیاJPAكه نمونه های از كلاس را از طریق سازندگان بدون پارامتر ایجاد می كنند ، آسان تر می كند.

class Invoice(val customerName: String = "")

ایجاد instance ها درکلاس

برای ایجاد نمونه ای از کلاس ، به سازنده می گوییم که یک متد معمولی است.

val invoice = Invoice()

val customer = Customer("maysam")

 

توجه داشته باشید که زبان کاتلین کلمه کلیدی جدیدی ندارد.

 

وراثت(Inheritance)

کلیه کلاسهای کاتلین دارای یکsuperclassمعمولیAnyهستند، این یکsupercalssپیش فرض برای یک کلاس است کهsupertypes از آن نیست.

class Example //به طور ضمنی از هر کسی به ارث می برد

 

هرکدام سه روش دارد:

equals()

 hashCode() 

 toString()

بنابراین، آنها برای کلیه کلاس های کاتلین تعریف می شوند. برای اعلام یکsupertypeصریح، نوع را بعد از : درheadکلاس قرار میدهیم.

open class Base(p: Int)

class Derived(p: Int) : Base(p)

اگر کلاس مشتق شده دارای یک سازنده اصلی باشد، می توان کلاسbase را با استفاده از پارامترهای سازنده اولیه در آنجا نوشت.اگر کلاس مشتق شده دارای سازنده اصلی نباشد، پس از آن هر سازنده ثانویه بایدbase typeرا با استفاده از کلید واژهsuperشروع کند، یا به سازنده دیگری که این کار را انجام می دهد واگذار کند. توجه داشته باشید که در این حالت سازنده های ثانویه مختلف می توانند سازنده های مختلفی ازbase typeباشند.

class MyView : View {
    constructor(ctx: Context) : super(ctx)

    constructor(ctx: Context, attrs: AttributeSet) : super(ctx, attrs)
}

Overriding methods درزبان کاتیلن

همانطور که قبلاً نیز اشاره کردیم ، ما به بیان صریح و روشن در کاتلین می پردازیم. بنابراین،کاتلین برایoverridable members نیاز به اصلاحات صریح دارد:

open class Shape {
    open fun draw() { /*...*/ }
    fun fill() { /*...*/ }
}

class Circle() : Shape() {
    override fun draw() { /*...*/ }
}

اگرoverrideرا برای ()Circle.drawننویسیم کامپایلر کد ما را اجرانمی کند وکامپایل نمیشود

اگر هیچ تغییری در یک عملکرد وجود نداشته باشد، مانند ().Shape.fillتعریف متد با همان امضا در زیر کلاس غیرقانونی است، چه باoverride یا بدونoverride

open modifier هیچ تأثیری در هنگام اضافه شدن به اعضای یک کلاسfinalندارد.

عضوی که از آنoverride شدهopenاست اگر می خواهیدoverride کردن مجدد از آن را منع کنید ازfinalاستفاده کنید

open class Rectangle() : Shape() {
    final override fun draw() { /*...*/ }
}

 

Overriding properties در زبان کاتلین

Overriding propertiesبه روشی مشابه روش های غالب عمل می کند.propertiesهای  در یکsuperclassتعریف میکنیم وقتی که یک کلاس دیگر را از این کلاس مشتق می کنیم برای استفاده از آنoverrideمی کنیم و همچنین باید یکtypeداشته باشند.

open class Shape {
    open val vertexCount: Int = 0
}

class Rectangle : Shape() {
    override val vertexCount = 4
}

 

شما میتوانیدpropertyکه باvalتعریف شده  را باvarبازنویسی (override)کنید.

شما میتواند یک متغیر را باval تعریف کنید و متدgetآن ازvalاستفاده کند و متدset آن را باvar تعریف کنید.

توجه داشته باشید که می توانید از کلید واژهoverrideبه عنوان بخشی از propertyدر سازنده اصلی استفاده کنید.

interface Shape {
    val vertexCount: Int
}

class Rectangle(override val vertexCount: Int = 4) : Shape // Always has 4 vertices

class Polygon : Shape {
    override var vertexCount: Int = 0  // Can be set to any number later
}

 

فرا خوانیsuperclass و implementation

کد در یک کلاس مشتق شده می تواند توابعsuperclassو پیاده سازی های دسترسیpropertyرا با استفاده از کلمه کلیدیsuperفراخوانی کند.

open class Rectangle {
    open fun draw() { println("Drawing a rectangle") }
    val borderColor: String get() = "black"
}

class FilledRectangle : Rectangle() {
    override fun draw() {
        super.draw()
        println("Filling the rectangle")
    }

    val fillColor: String get() = super.borderColor
}

در داخل یک کلاس داخلی ، دسترسی به superclassبیرونی با کلمه کلیدیsuper  با نام کلاس بیرونی انجام می شود به عنوان مثال: super@Outer

open class Rectangle {
    open fun draw() { println("Drawing a rectangle") }
    open val borderColor: String get() = "black"
}

class FilledRectangle: Rectangle() {
    override fun draw() { /* ... */ }
    override val borderColor: String get() = "black"

    inner class Filler {
        fun fill() { /* ... */ }
        fun drawAndFill() {
            super@FilledRectangle.draw() // Calls Rectangle's implementation of draw()
            fill()
            println("Drawn a filled rectangle with color ${super@FilledRectangle.borderColor}") // Uses Rectangle's implementation of borderColor's get()
        }
    }
}

کلاس های Abstract

یک کلاس و برخی از اعضای آن ممکن استabstractتعریف شوند. عضوabstractدر کلاس خود پیاده سازی ندارد. توجه داشته باشید که لازم نیست یک کلاسabstractیا عملکردی را با انوتیشن نشان دهیم.ما میتوانیم عضوی از کلاسی کهabstract نیست را به صورتabstract بازنویسی کنیم.

open class Polygon {
    open fun draw() {}
}

abstract class Rectangle : Polygon() {
    override abstract fun draw()
}

 

ompanion objects در کاتلین

اگر شما نیاز به نوشتن عملکردی دارید که میخواهید بدون نمونه سازی از کلاس می از آن استفاده کنید اما نیاز به دسترسی به داخل یک کلاس دارد (برای مثال ، یک  متدfactory)، می توانید آن را به عنوان عضوی از یک شیء در آن کلاس بنویسید. حتی به طور خاص تر، اگر شما یک شیء را داخلcompanion objectتعریف کنید، می توانید فقط با استفاده از نام کلاس به اعضای آن دسترسی پیدا کنید.

امیدوارم این مقاله نیز براتون مفید واقع شده باشد.

سوالات و مشکلات خود را در بخش نظرات مطرح کنید.

 

 

 

 

 

 

تگ‌ها
اشتراک

0 نظرات