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

Classes

Classes are the main building blocks of any object-oriented programming language. The concept of a class was first studied by Aristotle. He was the first one to come up with the concept of a class of fishes and a class of birds. All objects, despite being unique, are part of a class and share a common behavior.

A class enables you to create your own type by grouping together methods and variable of other types. Think of a class as a blueprint; it describes the data and the behavior of a type.

Classes are declared by using the class keyword, as shown in the following example:

    class Deposit { 
    } 

Compared to Java, you can define multiple classes within the same source file. The class keyword can be preceded by the access level. If it is not specified, it will default to public; this means anyone can create objects of this class. The name of the class follows the keyword and the curly braces contain the class body where the behavior and data are defined—fields, properties, and methods.

The class construct supports the first characteristic of an OOP language—encapsulation. The idea behind it is that you want to keep each class discrete and self-contained. This allows you to change its implementation without affecting any part of the code that uses it, as long as it continues to meet the terms of its contract.

So far, I have used the terms class and object interchangeably. As we move forward, we will make a clear distinction between the two. An object is a runtime instance of a class definition. In order to create an instance of a class, you need to call the constructor. In the preceding example, the Deposit class gets an empty constructor generated by the compiler automatically. But if you want to provide a constructor, you need to write the following:

    class Person constructor(val firstName: String, val lastName:  String, val age: Int?) {} 
 
    fun main(args: Array<String>) { 
      val person1 = Person("Alex", "Smith", 29) 
      val person2 = Person("Jane", "Smith", null) 
      println("${person1.firstName},${person1.lastName} is  ${person1.age} years old") 
     println("${person2.firstName},${person2.lastName} is  ${person2.age?.toString() ?: "?"} years old") 
    } 

If you have been a Java developer for years, you will most likely have noticed the lack of the new keyword. In Java, to create a new instance of a given class, you always use new MyClass. This is not the case in Kotlin, though; you don't need to use it. If you do, you will actually get a compilation error since it is not a recognized keyword.

 

For a Scala developer, the preceding code would look very familiar, though you would probably ask why you have to use the constructor keyword. Doesn't the compiler know it is  a constructor? The answer is that you don't have to use the constructor keyword unless you specify access modifiers or annotations. The preceding constructor is called the primary constructor. I guess your next question will be; If you want to validate the incoming parameters, how can this primary constructor contain code? The answer lies with the init block. To have any code run as part of your primary constructor, you would have to perform the following:

    class Person (val firstName: String, val lastName: String, val  age: Int?){ 
      init{ 
        require(firstName.trim().length > 0) { "Invalid firstName  argument." } 
        require(lastName.trim().length > 0) { "Invalid lastName  argument." } 
        if (age != null) { 
          require(age >= 0 && age < 150) { "Invalid age argument." } 
        } 
      } 
    } 

Now the validation code will run as part of your primary constructor. The require method will throw IllegalArgumentException with the message you have provided if the expression given evaluates to False.

I am sure some of you would ask—how does it work with all three arguments? Are they created as public fields of the class? The answer is, no. There are properties. If you are accustomed to the .NET world, you will immediately know what it is all about. We will discuss this in detail in Chapter 6, Properties.

How does one create a new instance of Person and grab the values of all the three fields when using the class from Java code? This is done through the getter functions that any Java developer is accustomed to as follows:

    Person p = new Person("Jack", "Miller", 21); 
    System.out.println(String.format("%s, %s is %d age old",  p.getFirstName(), p.getLastName(), p.getAge()));

The third parameter of the constructor is a nullable integer; it would be good to have the option of not having to actually type null when instantiating an instance for which we don't have the age. Kotlin is a modern language that supports default values for a method parameter, but on this occasion let's just say it doesn't do so. So, we want to have a second constructor for which we only pass the first and last name as follows:

    constructor(firstName: String, lastName: String) :  this(firstName, lastName, null) 

For any secondary constructor, you need to call the primary constructor through this, and pass all the parameters required. Now you can create a new Person object as follows:

    val person2 = Person("Jane", "Smith") 

If you don't want to have your constructor accessed directly, you should mark it private, protected, or internal. A typical singleton design consists of providing a private constructor and then having the getInstance() method give you that one instance of that class at runtime. When defining abstract classes you should flag your constructor visibility as protected; this way it can only be called by the derived classes. We will see this shortly as we cover inheritance. Given your module logic, you could expose classes whose instances can and should only be created within your module as follows:

    class Database internal constructor(connection:Connection) { 
    } 

Prefixing your constructor arguments with val or var is not a must; if you don't want the getter (or setter if you use var) to be generated, you can always do the following:

    class Person2(firstName: String, lastName: String, howOld:  Int?) { 
      private val name: String 
      private val age: Int? 
 
      init { 
        this.name = "$firstName,$lastName" 
        this.age = howOld 
      } 
 
      fun getName(): String = this.name 
 
      fun getAge(): Int? = this.age 
    } 

Try creating a new instance of this class and then use the dot operator to prompt IntelliSense to display the available methods on your object. Unlike the first example, the three parameters are not translated into fields; the pop-up window will display two methods, named getName and getAge.

主站蜘蛛池模板: 兰溪市| 株洲县| 成安县| 绥棱县| 连江县| 五寨县| 九江市| 澄城县| 渝北区| 扎赉特旗| 延边| 开原市| 鄂州市| 禄丰县| 饶阳县| 吉木萨尔县| 金阳县| 调兵山市| 信阳市| 嘉义市| 满洲里市| 同心县| 黄龙县| 理塘县| 攀枝花市| 临武县| 安阳县| 金溪县| 崇礼县| 永胜县| 交口县| 鞍山市| 谢通门县| 淮阳县| 北流市| 塔城市| 涟源市| 漳州市| 遂川县| 灵璧县| 浦东新区|