官术网_书友最值得收藏!

Inheritance

Inheritance is fundamental to object-oriented programming. It allows us to create new classes that reuse, extend, and/or modify the behavior of preexisting ones. The preexisting class is called the super (or base or parent) class, and the brand new class we are creating is called the derived class. There is a restriction on how many super classes we can inherit from; on a JVM, you can only have one base class. But you can inherit from multiple interfaces. Inheritance is transitive. If the C class is derived from the B class and the B class is derived from a given A class, then the C class is a derived class of A.

A derived class will implicitly get all the parent classes (and the parent's parent class, if that is the case) fields, properties, and methods. The importance of inheritance lies in the ability to reuse code that has already been written and, therefore, avoid the scenario where we have to re-implement the behavior exposed by the parent class. A derived class can add fields, properties, or new methods, thus extending the functionality available through the parent. We would say that the B class, the derived one, specializes the A class, the parent. A simpler example is to think of the animal kingdom chart. At the top, we have the animal, followed by vertebrates and invertebrates; the former is further split into fish, reptile, mammals, and so on. If we take the yellow-fin tuna species, we can look at it as a specialized type of fish.

The next illustration shows a simple class hierarchy. Let's say you write a system to deal with payments. You will have a class called Payment that holds an amount and a CardPayment class to take such payments:

You must have noticed the presence of another entity called Any in the preceding screenshot. Every time you construct an entity that doesn't take any parent, it will automatically get this class as its parent. You will probably think Any is the Object class, the super/parent class of any class defined in Java. However, this is not the case. If you pay attention to the methods defined by the Any class, you will notice the Any class is a subset of those found on the Java Object class. So how does Kotlin deal with Java object references? When the compiler sees such an object, it will translate it into Any, and then it will make use of extension methods to complete the method set.

Let's implement the preceding code and see how inheritance is written in Kotlin as follows:

    enum class CardType { 
      VISA, MASTERCARD, AMEX 
    } 
 
    open class Payment(val amount: BigDecimal) 
class CardPayment( amount: BigDecimal,
val number: String,
val expiryDate: DateTime,
val type: CardType ): Payment(amount)

We have created our classes based on the spec we just saw. CardType is an enumeration type, as hinted in the definition. The definition of Payment has introduced a new keyword called open. Through this keyword, you are basically saying the class can be inherited from. The designers of Kotlin have decided the default behavior is to have the classes sealed for inheritance. If you have programmed in Java, you will have come across the final keyword, which does exactly the opposite of open. In Java, any class which hasn't been marked as final can be derived from. The definition of CardPayment marks the inheritance through a semicolon. The : Payment translates into CardPayment, which extends from Payment. This is different from Java where you would use the extends keyword. Any developers with a C++ or C# background will be very familiar with the construct.

In the preceding code, our CardPayment class has a primary constructor. Therefore, the parent one has to be called on the spot, hence Payment(amount). But what if our new class doesn't define a primary constructor? Let's extend our class hierarchy to add a new type, named ChequePayment:

    class ChequePayment : Payment { 
      constructor(amount: BigDecimal, name: String, bankId: String) :  super(amount) { 
        this.name = name
        this.bankId = bankId 
      } 
      var name: String
        get() = this.name
      var bankId: String
        get()  = this.bankId 
    } 

Since we have chosen to avoid the primary constructor, the definition of a secondary constructor has to call the parent one. This call needs to be the first thing our constructor does. Hence, the body of our constructor is preceded by super(args1,args2...). This is different from Java, where we would have moved this call as the first line in our constructor body.

In this example, we inherit from one class only—as we said earlier, we can't inherit from more than one class. However, we can inherit from multiple interfaces at the same time. Let's take a simple example of an amphibious car—it is a boat as well as a car. If you were to model this, we might have two interfaces—Drivable and Sailable , and we would have our amphibious car extend both of them:

    interface Drivable { 
      fun drive() 
    } 
    interface Sailable { 
      fun saill() 
    } 
    class AmphibiousCar(val name: String) : Drivable, Sailable { 
      override fun drive() { 
        println("Driving...") 
     } 
      override fun saill() { 
        println("Sailling...") 
      } 
    } 

Remember our class automatically derives from Any; it is as if we had written class AmphibiousCar(val name:String):Any, Drivable, Sailable. When we inherit an interface, we have to provide an implementation for all its methods and properties, or we have to make the class abstract:

    interface IPersistable { 
      fun save(stream: InputStream) 
    } 
 
    interface IPrintable { 
      fun print() 
    } 
 
    abstract class Document(val title: String)  
 
    class TextDocument(title: String) : IPersistable, Document(title),  IPrintable { 
  override fun save(stream: InputStream) { 
        println("Saving to input stream") 
      } 
 
      override fun print() { 
        println("Document name:$title") 
      } 
    } 

We will talk shortly about abstract classes. There is no restriction as to how many interfaces you can inherit from and the order in which you want to specify them. 

主站蜘蛛池模板: 鱼台县| 班戈县| 柘荣县| 道孚县| 黎川县| 长沙市| 玉溪市| 商河县| 偃师市| 南陵县| 昭苏县| 崇左市| 泰兴市| 腾冲县| 罗田县| 临漳县| 永川市| 乌拉特后旗| 曲阜市| 芮城县| 平原县| 芒康县| 额尔古纳市| 镇宁| 武汉市| 钟山县| 呼和浩特市| 岱山县| 威宁| 仁布县| 巍山| 搜索| 渭南市| 大厂| 青河县| 荔浦县| 临沭县| 易门县| 淄博市| 横峰县| 峡江县|