- Learn Kotlin Programming(Second Edition)
- Stephen Samuel Stefan Bocutiu
- 1086字
- 2021-06-24 14:13:32
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.
- Leap Motion Development Essentials
- Learning RxJava
- Cross-platform Desktop Application Development:Electron,Node,NW.js,and React
- Java應用開發(fā)與實踐
- 從0到1:HTML+CSS快速上手
- Building Cross-Platform Desktop Applications with Electron
- Effective Python Penetration Testing
- Learn React with TypeScript 3
- AIRIOT物聯(lián)網(wǎng)平臺開發(fā)框架應用與實戰(zhàn)
- ElasticSearch Cookbook(Second Edition)
- Python項目實戰(zhàn)從入門到精通
- 零基礎(chǔ)學Kotlin之Android項目開發(fā)實戰(zhàn)
- App Inventor創(chuàng)意趣味編程進階
- Processing創(chuàng)意編程指南
- Learning C++ by Creating Games with UE4