The Programmers Guide To Kotlin - The Class & The Object |
Written by Mike James | ||||
Monday, 24 July 2017 | ||||
Page 2 of 3
Initializer BlocksThere is one more twist in the Kotlin class declaration. You can define initializer blocks. These are blocks of code within the class declaration that are run before the constructor. Even though they run before the constructor the parameters passed to the constructor are available to them - they act like code inserted into the start of the constructor. In Kotlin all initialization occurs in the order the code is listed and before the constructor is run, but with the constructor parameters fully defined. That is the intializer looks like a block of code that is inserted into the very start of every constructor. For example:
The init block runs before the constructor but Name is set to "Mickey Mouse". This order of execution can be confusing at first, but it is simple, logical and, as long as you understand it, shouldn't cause any errors. You can have as many init blocks and as many constructors as you need and you don't need to define an explicit primary constructor. Constructor Chaos?At this point you might be confused as to how all these facilities fit together - it seems we have too many ways of defining what can happen when an instance is created. The important thing to note about the initializer is that it runs as if it was the initial code for each of the constructors - hence it is the ideal way to carry out anything that has to happen irrespective of which constructor is used. When creating a class you have a number of different levels of constructor complexity you can adopt.
In most cases all you need is a primary constructor and possibly an initalizer block. Class Members - Methods & PropertiesOf course, as well as constructors and init blocks a class can have properties and methods and so far we haven't said much about them, There isn't much to say about methods - you simply define a function within a class and call it using the usual dot notation. There are a few things to say about properties, however. Properties can be read/write or read only as declared using var or val. Properties declared using var have default getters and setters and those declared using val have only a getter i.e. val properties are read only. All properties are accessed via getter and setter functions and, unlike in Java, you don't have to explicitly create them - the compiler will do the job for you. It will also automatically put get or set in front of the property's name so that you can use Java properties implemented in this way without having to modify property names. Notice that a class cannot have a simple field, i.e. a variable that is directly accessible without the use of a getter or setter. All variables defined within a class declaration are properties. If you want a custom getter or setter you simply define them after the property declaration. The only thing you have to remember is that the property has a default backing field which can be accessed using the identifier field. This means that within the getter and setter you refer to the property value as field. For example:
In this case the setter will only change the value of the property if it is positive. Also notice that, unlike in languages such as Java. you don't have to call the getters and setters. You simply assign and make use of the property and the getter and setter is called as needed. For example:
To be clear, the assignment to myProp calls the setter and the use of myProp in the printlin calls the getter. If you want to call Java code then you can use getter and setter Java properties as if they were Kotlin properties, i.e. without putting get or set into the property name or calling a function. If you want to call a Kotlin method from Java you simply use the corresponding getProperty and setProperty functions. Behind the scenes, Kotlin uses the same code to create getter/setter properties as Java. If you want to have your own backing variable you can simply declare one and use it:
Notice that in this case you can't initialize the property because it doesn't have a default backing variable. Instead you have to initialize the backing variable itself. Late Initialized PropertiesMuch of this chapter has been about setting up and initializing properties. If the property is a non-null type then it has to be initialized in the constructor code. However there are case where the property is more correctly initialized by some other function. You can deal with this by initializing the property to a default value or you can use a nullable type and have to deal with null checks from then on or you can mark the property with lateinit. This only works for var non-null, non-primitive properties defined in the body of the class. The property can remain undefined for as long as you like, but if you try to access it before it is initalized you will generate an exception. For example: class myClass { In this case it is supposed that the setMessage function will be called before the property is used. If you do use it uninitialized:
then you will see the error message:
However if you do initalize it: var myObject = myClass()myObject.setMessage() println(myObject.myMessage) everything works. Class Members - Inner ClassesClasses can have functions and properties as members and they can also have other classes. A nested class is defined within another class. It is local to the containing or outer class in that it isn't visible outside of the containing class. For example, MyNestedClass is local to MyClassA:
It can be used by methods inside MyClassA but it is inaccessible from anywhere else. By default nested classes cannot access the members of the outer class. That is, if you try:
you will find that myString is unresolved and there is an error. However, if you mark the nested class as inner then it can access the outer class's members That is, with the addition of inner, myInnerMethod can now access myString in the outer class:
Inner classes are useful if you need to define classes that are useful to another class and not generally useful. If you need to instantiate a lot of inner class objects then it makes sense. However, if you only need a single instance then using a Kotlin object makes better sense as you don't have to declare a class first. |
||||
Last Updated ( Monday, 24 July 2017 ) |