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

کلاس ها و وراثت در زبان کاتلین
فهرست مقاله [نمایش]

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

    کلاس های کاتلین با استفاده ازکلمه کلیدی 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 تعریف کنید، می توانید فقط با استفاده از نام کلاس به اعضای آن دسترسی پیدا کنید.

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

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

     

     

     

     

     

     


    • نویسنده: میثم بابائی

    ارسال دیدگاه

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


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