Object oriented concepts

  • encapsulation

    Encapsulation is the core idea of object orientation. It encapsulates the properties and behaviors of objects without letting the outside world know the specific implementation details. This is the encapsulation idea. For example, a user can use a computer by tapping on the keyboard with his or her fingers. He or she does not need to know how the computer works, even though he or she may happen to know how the computer works, but he or she does not rely entirely on the details of how the computer works.

  • inheritance

    Inheritance mainly describes the relationship between classes. Through inheritance, the functions of the original class can be extended without the need to rewrite the original class. For example, there is a car class, which describes the common characteristics and functions of the car, and the car class should not only contain the characteristics and functions of the car, but also increase the unique functions of the car. At this time, the car class can inherit the car class, and add the car characteristics in the car class separately.

  • polymorphism

    Polymorphism refers to the duplication of names allowed in programs. It means that when attributes and methods defined in one class are inherited by other classes, they can have different data types or exhibit different behaviors, which makes the same attribute and method have different semantics in different classes.

classClass: An abstraction of an object

Create a class

A class is an abstraction of an object that describes the common characteristics and behavior of a group of objects. Member variables and member functions can be defined in a class. Member variables are used to describe the characteristics of the object, also known as attributes, and member functions are used to describe the behavior of the object, which can be referred to as functions or methods for short.

class Person{
    var name = "X"
    var age = 18
    fun sayHello(a) {
        println("name:$name\nage:$age")}}Copy the code

Create an object

var p=Person()
Copy the code

An instance object of the Person class is created.

Practical application:

class Person {
	// Member attributes
	var name = "X"
	var age = 18
	// Member methods
	fun sayHello(a) {
		println("Name:$name\nAge:$age")}}fun main(a) {
	val p = Person()
	p.sayHello()
    // Name:X
	// Age:18
	println("Name:${p.name}")
    // Name:X
	p.name="Z"
	println("Name:${p.name}")
    // Name:Z
}
Copy the code

Class to encapsulate

Class encapsulation means that when defining a class, the attributes in the class are privatized. That is, the private keyword is used to modify the attributes. The private attributes can only be accessed in the class in which they reside. To make these private attributes accessible to the outside world, you need to provide some public methods with public decorations. (This sentence is not understood at present).

class Student {
	var name:String = ""
	private var age:Int = 0

	fun setAge(age:Int) {
		if (age>=0) {
			this.age = age
			println("Age:$age")}else {
			println("WRONG.")}}fun sayHello(a) {
		println("Name:$name\nAge:$age")}}fun main(a) {
	val stu = Student()
	stu.name = "Z"
	stu.setAge(-4)
	stu.sayHello()
	stu.setAge(3)}Copy the code

Where the this keyword refers to the current object of the class, intended to distinguish it from the private property age in the Student class.

The constructor

A constructor is a special member of a class that is called automatically when the class instantiates an object. Kotlin’s constructors fall into two categories — primary and secondary.

In simple terms, the intent of a constructor is to simply pass in arguments and use them (just like a function) when the class is initially instantiated.

Principal constructor:constructor

A class can have one primary constructor and multiple secondary constructors. The constructor is preceded by the class header after the class name. If the main constructor does not have any annotations or visibility modifiers (such as public), the constructor keyword may be omitted.

The syntax for the constructor is as follows:

class ClassName constructor([args1,args2,args3]) {}
Copy the code
  • When defining a class, the Kotlin compiler generates a no-argument constructor for it by default if the specified constructor is not displayed, just as in Java.

    class ClassName constructor() {}  // The first way
    class ClassName() {}  // The second way
    Copy the code
  • Parameterized constructor: Assigns values to attributes via parameterized constructors. The primary constructor cannot contain any code, and the initialization code can be placed in the initialization code section, which is prefixed with the init keyword.

    class Clerk constructor(username:String) {
    	init{
    		println("I am $username")}}fun main(a) {
    	var clerk=Clerk("Z")}// I am Z
    Copy the code

    In Kotlin’s Book From The Basics to the Field, the example of a principal constructor is quite superfluous:

    class Clerk constructor(username:String) {
        var name:String
        init{
            name=username
            println("I am $name")}}Copy the code

    The superfluous thing is that the var name:String line and the following assignments are completely unnecessary. After reading below, the author deliberately introduces this keyword. That is, he tries to change the constructor username and the class member variable name to name, and then deliberately adds this.name to init to distinguish them. Since we have studied this before, we will not go into details here.

    class Clerk constructor(name:String) {
        var name:String
        init{
            // Where this.name refers to the member variable name of the class
            this.name = name
            println("I am $name")}}Copy the code

Secondary constructor:constructorandthis

In Kotlin, multiple sub-constructors can be defined, again using the constructor keyword, except that the sub-constructor resides in the class body.

The secondary constructor is used in the following scenarios, that is, if the primary constructor has only one name attribute, and there is a case where the name attribute and the age attribute are assigned at the same time, we need to add another function, that is, the secondary constructor. The secondary constructor must call either the primary constructor or another secondary constructor as this (argument list).

class Workers constructor(name:String) {
	init {
		println("I am $name.")}constructor (name:String,age:Int) :this(name) {
		println("I am $name,\nI am $age years old.")}constructor (name:String,age:Int,sex:String):this(name,age) {
		println("I am $name,\nI am $age years old,\nI am a $sex.")}}fun main(a) {
	var person = Workers("Z".18."man")}Copy the code

As you can see from the code, the first subconstructor inherits from the autonomous constructor, and the second subconstructor inherits from the first subconstructor. Not only is the second sub-constructor called, but both the first sub-constructor and the primary constructor are called.


Class inheritance

inheritance

In Kotlin, class inheritance refers to building a new class from an existing class. The new class is called a subclass, and the existing class is called a parent class. The subclass automatically has all the inheritable properties and methods of the parent class.

This concept is consistent with Python. Syntactically, the parent class should be preceded by the open keyword (because all classes in Kotlin use the final keyword by default and cannot be inherited), and subclasses should be declared with :FatherClass(), as shown in the following example:

open class Father() {
    fun sayHello(a) {
        println("Hello")}}class Son:Father() {}

fun main(a) {
    var son = Son()
    son.sayHello()  // "Hello"
}
Copy the code
  • A subclass can inherit only one parent class.
  • Multiple subclasses can inherit from a parent class.
  • Multi-level inheritance is possible, such as A inheriting FROM B and B inheriting from C, in which case A can also be considered A subclass of C.

Inherited rewriting

This refers to the fact that sometimes a subclass does not inherit completely from its parent class and needs to modify some of its inherited methods or properties. This modification is called method or property overrides.

  • In the parent class, methods or attributes that need to be overridden need to be added firstopenThe keyword.
  • Used before overriding a method or property in a subclassoverrideThe keyword.
open class Father() {
	open var name = "Z"
	open var age = 25
	fun sayHello(a) {
		println("Hello,I am $name,I am $age years old.")}}class Son():Father() {
	override var name = "X"
	override var age = 15
}

fun main(a) {
	val father = Father()
	val son = Son()
	father.sayHello()
	son.sayHello()
    //Hello,I am Z,I am 25 years old.
    //Hello,I am X,I am 15 years old.
}
Copy the code

super: Call the parent class again after overwriting

As mentioned earlier, you need super.func if you still want to access the parent class’s properties or methods because you have new methods or properties.

A BORING example:

open class Father() {
	open var name = "Z"
	open var age = 25
	open fun sayHello(a) {
		println("Hello,I am $name,I am $age years old.")}}class Son():Father() {
	override var name = "X"
	override var age = 15
	override fun sayHello(a) {
		super.sayHello()
		println("Hello,I am ${super.name}'s son,I am $name,I am $age years old.")}}fun main(a) {
	val son = Son()
	son.sayHello()
}
Copy the code

One little piece of information I didn’t understand,Anyclass

All classes in Kotlin inherit from Any, which is the parent of all classes. If a class is declared without a parent, the default parent is Any, which is automatically mapped to the Java.lang.object class in Java when the program runs.

In Kotlin, all types are reference types that inherit from the parent class Any, which provides three methods by default: equals(), hashCode(), and toString().

Abstract classes and interfaces

An abstract classabstract

When defining a class, it is often necessary to define methods that describe the behavior of the class, but sometimes the implementation of these methods is uncertain. Therefore, it can be defined as an abstract method, which is modified with the abstract keyword. This method has no method body and needs to be implemented when it is used. When a class contains an abstract method, the class must be defined as an abstract class using the abstract keyword.

In other words, the actual need is to define a method in the class, but the content of the method is not known, so the method can be defined as abstract method, with abstract method, the class of the method must be defined as abstract class.

However, classes that have abstract methods must declare abstract classes, but the abstract class must not have abstract methods in it.

Abstract classes cannot be instantiated because abstract methods cannot be called. If you want to call, you need to create a subclass.

As follows:

abstract class Animal() {
	abstract fun eat(a)
}

class Monkey(var food:String):Animal() {
	// var food = food
	override fun eat(a) {
		println("Monkeys are eating $food.")}}fun main(a) {
	var monkey = Monkey("banana")
	monkey.eat()
    // Monkeys are eating banana.
}
Copy the code

interfaceinterface

If all the methods in an abstract class are abstract, the class can be defined in another way, that is, an interface. An interface is a special abstract class. When you define an interface, you use the interface keyword to declare:

interface Animal {
    fun eat(a)
}
Copy the code
  • eat()noabstractKeyword modifier, because the interface has it by default
  • AnimalNo parenthesis
  • Like abstract classes, interfaces require subclasses to instantiate to invoke methods

Class inheritance interface

interface Animal {
	fun eat(a)
}

class Monkey(var food:String):Animal {
	override fun eat(a) {
		println("Monkeys are eating ${food}.")}}fun main(a) {
	val monkey = Monkey("banana")
	monkey.eat()
}
Copy the code

Interface inherits interface (actually the same thing)

interface Animal {
	fun eat(a)
}

interface Monkey:Animal {
	fun sleep(a)
}

class GoldenMonkey(var food:String):Monkey{
	override fun eat(a) {
		println("I am GoldenMonkey,I love $food.")}override fun sleep(a) {
		println("I am GoldenMonkey,I love sleep.")}}fun main(a) {
	var g = GoldenMonkey("banana")
	g.eat()
	g.sleep()
}
Copy the code

Of course, a class can accept multiple interfaces or abstract classes, separated by,.

Common class

Nested and inner classesinner

Nested classes and inner classes are nested classes within a class. The only difference between them is whether the inner class is preceded by an inner tag.

The essential difference is that the nested class does not have inner, so it cannot access variables or methods outside of itself, as shown in the following example:

class A{
    var name="A"
    class B{
        fun sayHello(a) {
            println("Hello!$name!")}}}Copy the code

This code is incorrect because class B itself, as A nested class, does not have access to variables in class A.

But the inner class works:

class A{
    var name="A"
    inner class B {
        fun sayHello(a){
            println("Hello $name.")}}}fun main(a) {
    A().B().sayHello()
}
Copy the code

So that’s true.

Enumeration classenum

Each enumerated constant is an object, separated by commas, and preceded by the enum keyword.

enum class Week{
    Monday,Tuesday,Wednesday,Tuesday,Friday,Saturday,Sunday
}
Copy the code

Enumerated classes support constructors * (In simple terms, constructors are intended to simply pass in arguments and use them (just like functions) when the class is initially instantiated.) *

enum class Week(val what:String, val doSomething:String) {
	Monday("Mon"."Work"),
    Tuesday("Tue"."Party"),
    Wednesday("Wed"."Work"),
    Thursday("Thu"."Work"),
    Friday("Fri"."Work"),
    Saturday("Sat"."Overtime"),
    Sunday("Sun"."Rest")}Copy the code

Seal typesealed

Only one instance of each enumerated constant exists, whereas a subclass of a sealed class can have multiple instances of containable state.

  • The sealed class must be decorated with the sealed keyword.
  • Because the constructor of a sealed class is private, subclasses of a sealed class can only be defined inside the sealed class or in the same file.
sealed class A {
	class A1:A() {}
	class A2:A() {}
	class B() {}}class A3:A() {}
Copy the code

Where, the subclasses of sealed class A are A1, A2, A3, and class B belongs to the nested class of A.

== Note that == : Sealed classes work when subclasses are countable, while enumerated classes work when instances are countable.

Data classesdata

Data classes cannot be modified with the keywords abstract, open, sealed, or inner.

In real development, data classes are often used to store data information, which is typically passed through the class’s main constructor.

data class Man(var name:String,var age:Int) {
	init {
		println("Name=$name\nAge:$age")}}fun main(a) {
	var man:Man = Man("Z".20)}Copy the code

The singleton patternobject

The singleton pattern is that there is only one instance of the class during program execution. Just as there is only one sun in the world, if we were to design a sun class now, the class would have to have only one instance object, otherwise it would be a violation of reality.

object SingleMode {
	var s = "SingleMode"
	fun sayHello(a) {
		println("Hello,I am $s.")}}fun main(a) {
	SingleMode.s = "X"
	SingleMode.sayHello()
	SingleMode.s = "Z"
	SingleMode.sayHello()
    //Hello,I am X.
    //Hello,I am Z.
}
Copy the code

Two characteristics can be seen:

  • The biggest feature of a singleton class is that it can be passed directlyClass name. Member nameYou do not need to create an instance object of the class, because throughobjectKeyword When you create a singleton class, the singleton object of the class is created by default. Therefore, when you call properties and functions in the class, you do not need to recreate the instance object of the class.
  • A singleton class has only one instance object, but can be called repeatedly, modify its properties, and call functions.

Associated objectcompanion object

Companion objects are initialized when the class is loaded and have the same life cycle as the class.

Defining companion objects is identified by the Companion keyword. Since there is only one companion object in each class, it is also possible to omit the name of the companion object and share it with other objects.

class Company {
	// Factory The associated object name can be written or omitted, since only one associated object can be used for a class
	companion object Factory {
		fun sayHello(a) {
			println("I am a Companion Object.")}}}fun main(a) {
	// Two call methods
	Company.Factory.sayHello()
	Company.sayHello()
}
Copy the code