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

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

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

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

class Invoice {
}

Java

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

class Empty
Java

Constructors( سازنده)

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

class Invoice constructor(firstName: String){
    
}
Java

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


class Invoice (firstName: String){

}
Java

سازنده اصلی میتواند کدی را نداشته باشد. کد اولیه را می توان در بلاک هایی نوشت که در اول کلاس قرار میگیرند که با کلمه کلیدی 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}")
        }
}
Java

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

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

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

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

Java

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

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

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

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

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

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

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

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

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

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

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

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

class Invoice(val customerName: String = "")

Java

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

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

val invoice = Invoice()

val customer = Customer("maysam")
Java

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

وراثت(Inheritance)

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

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

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

equals()

 hashCode() 

 toString()

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

open class Base(p: Int)

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

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

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

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

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

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

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

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

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

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

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

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

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

Java

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

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

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

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

شما میتوانید 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
}
Java

فرا خوانی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
}
Java

در داخل یک کلاس داخلی ، دسترسی به 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 ${}") // Uses Rectangle's implementation of borderColor's get()
        }
    }
}
Java

کلاس های Abstract

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

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

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

ompanion objects در کاتلین

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

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

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

اطلاعات نویسنده
  • نویسنده: میثم بابائی

ارسال دیدگاه

برای افزودن دیدگاه خود، نیاز است ابتدا وارد حساب کاربری‌تان شوید


دیدگاه کاربران