Classes templates for creating objects, and spaces for organizing functions and variables in a logical way.
Kotlin classes can have multiple constructors, one primary constructor and one or more secondary constructors.
The multiple constructors allow the class to be initialized in different ways, and each one must call the primary constructor first.
The primary constructor can not execute code, so the init block is used to execute code after the primary constructor as it runs once and only once after the primary constructor for each instance of the class.
classFooconstructor(varcount:Int,valcon:String='PrimaryConstructor'){// primary constructor, with default valueinit{println("Foo created with count $count by constructor $con")// only executed once, after primary constructor}constructor(stringCount:String):this(stringCount.toInt(),'Constructor1'){// call primary constructorprintln("Foo created with count $count")// only executed once, after primary constructor// execute more code if needed}constructor():this(0,'Constructor2')// call primary constructor}valfoo1=Foo(1)// call primary constructorvalfoo2=Foo("2")// call secondary constructorvalfoo3=Foo()// call secondary constructor/**1. Foo created with count 1 by constructor Primary Constructor2. Foo created with count 2 by constructor Constructor 12. Foo created with count 23. Foo created with count 0 by constructor Constructor 2*/
In the code above:
The Foo class has a primary constructor with two parameters; count is mandatory and con is optional with a default value.
Two secondary constructors are defined, each one calls the primary constructor first using the this() keyword.
Inheritance is way of passing common functionality between classes, it allows for code reuse and organization and defining the contracts between classes (using interfaces or abstract classes).
A subclass (child) can extend (inherit) from a superclass (parent) using the : symbol.
The super class must be open to allow inheritance, and the subclass must call the super class constructor.
In Kotlin, a class can only inherit from one super class, but can implement multiple interfaces.
abstract classes are way for defining some methods/properties that must be implemented by the subclass.
openclassAnimal{}classDog:Animal(){}classCat:Animal(){}funclassifyAnimal(animal:Animal):Unit=when(animal){isDog->println("animal is a Dog")isCat->println("animal is a Cat")else->println("animal is neither a Dog nor a Cat")}funmain(){valdog=Dog()valcat=Cat()valanimal:Animal=Animal()// animal is a Dog, but declared as Animal; we can not tell what it is at compile timeclassifyAnimal(dog)// animal is a DogclassifyAnimal(cat)// animal is a CatclassifyAnimal(animal)// animal is a Dog}
In the code above:
The Animal class is open to allow inheritance.
Dog and Cat inherit the Animal class.
The classifyAnimal function takes an Animal as a parameter, and uses the when expression to check the type of the animal.
Enums are a way of defining a type with a fixed set of values, or placing constraints on the values of a type.
Kotlin is a bit weird when dealing with enums, as they are considered Full Classes and can have properties and methods, while all other languages consider enums as Restricted values of integers.
Almost all class features are available in enums, except for inheritance and few other rules.
enumclassPossibleShapes(valsides:Int,sideNames:List<String>){Circle(1,listOf("radius")),Rectangle(4,listOf("width","height")),Triangle(3,listOf("base","height","hypotenuse"))}fundescribeShape(shape:PossibleShapes):Unit=when(shape){PossibleShapes.Circle->println("Circle has ${shape.sides} side(s): ${shape.sideNames}")PossibleShapes.Rectangle->println("Rectangle has ${shape.sides} side(s): ${shape.sideNames}")PossibleShapes.Triangle->println("Triangle has ${shape.sides} side(s): ${shape.sideNames}")}funmain(){describeShape(PossibleShapes.Circle)// Circle has 1 side(s): [radius]describeShape(PossibleShapes.Rectangle)// Rectangle has 4 side(s): [width, height]describeShape(PossibleShapes.Triangle)// Triangle has 3 side(s): [base, height, hypotenuse]}
In the above code:
The PossibleShapes enum has three values, each one has a number of sides and a list of side names.
The describeShape function takes a PossibleShapes as a parameter, and uses the when expression to check the type of the shape.