The official account is open for submission
Good articles are not afraid of no one to read, and there are profits
Stab contribute
Author: ze MAO links: jianshu.com/p/c2463a6140c5
Source: Jane book copyright belongs to the author, has authorized the original, prohibit unauthorized reprint
I. Summary of this paper
This article is a study note for <
>. If you need to run the corresponding code, you can visit the online environment try.kotlinlang.org.
Define the class inheritance structure
2.1
Interfaces in Kotlin
Kotlin’s interface can contain two types of methods:
-
Simple abstract methods
-
Contains abstract methods for the default implementation
01. Simple interface
-
A simple Kotlin interface is declared using the interface keyword, and all non-abstract classes that implement this interface need to implement the abstract methods defined in the interface.
-
Kotlin replaces the extends and implements keywords in Java with colons after class names. A class can implement multiple interfaces, but can only inherit from one class.
-
The Override modifier is used to mark methods and attributes of the overridden parent class or interface and is mandatory.
The following example defines an interface and demonstrates how to implement it, along with the abstract methods defined in the interface:
Define the default implementation of the method in the interface
We can provide a default implementation of the interface’s methods, defining the same methods as normal functions.
If a class implements two interfaces that define the same method and both provide a default implementation of the method, then the class must display the implementation of the method or it will report an error at compile:
03. Invoke the implementation of methods inherited from the interface
When calling an inherited implementation, use the same keyword super as in Java, followed by Angle brackets indicating the name of the parent class, and finally the name of the called method:
2.2
Access modifiers: open, final, abstract
01. General class
-
In Kotlin, classes and methods are final by default. If you want to allow subclasses of a class to be created, you need to use the open modifier to identify that class, and you need to add the open modifier to every property or method that is allowed to be overridden.
-
If you override a member of a base class, the overridden function also defaults to open. If you want to change this behavior, you can explicitly mark the overridden member as final.
02. An abstract class
We can declare a class as abstract. This class cannot be instantiated. An abstract class usually contains some abstract members that are not implemented and must be overridden in the subclass:
-
Abstract functions in abstract classes: without a function body, they are abstract by default, without a keyword, and their access is always open.
-
Non-abstract functions in abstract classes: The default is final, and if overridden, the open modifier is required.
The three access modifiers, open, final, and abstract, apply only to classes and cannot be used in interfaces:
-
Open: Used to declare that a class can be inherited, or that methods can be overridden by subclasses.
-
Final: Classes are not allowed to be inherited or methods are not allowed to be overridden.
-
Abstract: Declare an abstract class, or an abstract method in an abstract class.
When we need to override a method, we must add the override modifier.
2.3
Visibility modifier
Kotlin’s visibility modifiers include the following four types:
The modifier | Members of the class | The top statement |
---|---|---|
public | Visible everywhere | Visible everywhere |
internal | Visible in module | Visible in module |
protected | Visible in subclasses | — – |
private | Seen in class | Visible in the file |
The differences in visibility between Java and Kotlin include the following:
-
In Java, the default visibility is package private, whereas in Kotlin, the default visibility is public. Kotlin uses internal as an alternative to package visibility, which means “visible only within a module.”
-
Kotlin allows the use of private visibility in top-level declarations, including classes, functions, and attributes that are visible only in the file in which they are declared, which is a very useful way to hide subsystem implementation details.
-
Class extension functions do not have access to its private and protected members.
-
In Kotlin, an external class cannot see the private members of its inner class.
2.4
Inner and nested classes
In Kotlin, if we define a class inside a class, as Java does, it is not an inner class, but a nested class. The difference is that the nested class does not hold a reference to the outer class, that is, it is actually a static inner class:
To change its nested class into an inner class that holds a reference to an external class, use the inner modifier, and access the external class using this@{external class name}.
2.5
Sealed class: Defines a restricted class inheritance structure
Num and Sum inherit from the base class Expr, representing numbers and the Sum of two expressions, respectively. For subclasses that are not Expr, we need to provide an additional else operator.
If we add a new subclass to Expr, the compiler won’t notice the changes. If you forget to add a new branch, you choose the default option, which can lead to potential bugs.
Kotlin provides a solution to this problem: the Sealed class. Add a sealed modifier to the parent class to set a strict limit on the subclasses that can be created. All direct subclasses must be nested within the parent class. The previous example is modified as follows:
If we add a new subclass of Expr, Multi, and do not modify the logic in when, we will fail to compile:
The following information is displayed:
In this case, the Expr class has a private constructor that can only be called inside the class, and you cannot declare a sealed interface, because if you do, the Kotlin compiler cannot guarantee that no one can implement this interface in Java code.
3. Construction method
In Java, a class can declare one or more constructors, and Kotlin divides constructors into two categories:
-
Primary constructor: A primary, concise method that initializes a class and is declared outside the class body.
-
From constructor: declared inside the class body.
3.1
Initialization class: main constructor and initialization statement block
Suppose we need to define a User class with a read-only nickname attribute. The simplest way to do this is:
The bracketed block above is called the primary constructor and serves two purposes:
-
Indicates the constructor parameters.
-
Define the property initialized with these parameters, which is nikename.
The most explicit code for these two functions is shown below:
-
Constructor: Used to start a declaration of master and slave constructors.
-
Init: Introduces an initializer block that contains the code executed when the class is created and is used with the main constructor, which has syntactic limitations, which is why initializer blocks are used.
There are several points that can be simplified in the above example:
-
Statements placed in the initialization statement block can be combined with declarations of nikename, so the init statement can be removed.
-
You can cancel the constructor keyword if the main constructor has no annotations or visibility modifiers.
-
If the property is initialized with the corresponding constructor parameter, the code can be simplified by prefixing the parameter with the val keyword.
After the above three points, you will get the result of the simplification.
For a constructor, can also be used before in the Kotlin knowledge comb (2) | function calls and the definition of “described in the named parameter and the technique of the default parameter values, if all the constructor has a default value, the compiler will generate an additional constructor with no parameters to use all the default values.
In Java, if the parent class defines a constructor, then the super method must be used to initialize the parent class in the constructor of the subclass, for example:
/ / parent class.public class User { private String nikeName; User(String nikeName) { this.nikeName = nikeName; }}/ / subclass.public class TwitterUser extends User { public TwitterUser(String nikeName) { super(nikeName); }}
Copy the code
In Kotlin, we do this by providing the parent constructor parameter in the parent reference of the base class list:
If a class does not declare any constructor, a default constructor that does nothing is generated. If a subclass inherits it, the parent constructor must be explicitly called, even if it has no arguments.
If you want to ensure that your class is not instantiated by other code, you must mark the constructor as private. Let’s change the above example:
The reasons for the error are as follows:
In most real-world scenarios, the constructor of a class is very concise: it either has no parameters or is directly associated with the corresponding attribute of the parameter, which is the concise syntax designed for Kotlin’s main constructor.
3.2
Initialize the parent class in a different way
Most scenarios that require overloaded constructors in Java are covered by Kotlin’s support for named parameters and their default values.
Define from the constructor method
When we need to extend a framework to provide multiple constructors so that classes can be initialized in different ways, we need to use the constructor method from the constructor, as in the following code:
The running results are as follows:
02. Subclasses call the slave constructor of their parent class: super
If you want to extend this class, you can declare the same constructor and call the corresponding parent constructor using the super keyword:
The running results are as follows:
03. Subclasses call their other constructor: this
If you want to call another constructor of your own class from one constructor, use this:
The running results are as follows:
Note: If the class without the main construction method, then each from you must initialize the base class constructor (through the super keyword), or entrusted to another to do so the constructor (through this keyword), that is, each from a constructor must begin with an arrow outwards, and ended in any base class constructor, Just as Button’s slave constructor with two parameters does in the above example.
3.3
Implements properties declared in the interface
In Kotlin, interfaces can contain declarations of abstract attributes:
But the interface does not say whether the value should be stored in a support field or retrieved through a getter. The interface itself does not contain any state, so only the class that implements the interface stores the value when needed.
Here are three examples:
-
PrivateUser: This property is declared directly in the main constructor and implements the abstract property from User, so it is marked as Override.
-
SubscribingUser: With a custom getter implementation, this property does not have a support field to store its value, it only has a getter that gets a nickname from the email each time it is called.
-
FacebookUser: Associate the nickname property with the value at initialization.
In addition to declaring abstract properties, interfaces can also contain properties with getters and setters, as long as they do not reference a support field (which requires storing state in the interface, which is not allowed) :
-
Email: must be overridden in a subclass.
-
Nickname: has a custom getter that can be inherited by subclasses.
The running results are as follows:
3.4
Support fields are accessed through getters and setters
We have now learned how to use two attributes:
-
Properties that store values
-
Property that has a custom accessor that evaluates the value on each access
Next, we combine the two to implement a property that can both store a value and provide additional logic when the value is accessed and modified:
The running results are as follows:
Address is an attribute that supports a field. It differs from an attribute that does not support a field:
-
If explicitly referenced or the default accessor implementation is used, the compiler generates support fields for the property.
-
If you provide a custom accessor implementation and do not use field, the support field will not be rendered.
3.5
Modify the visibility of the accessor
The visibility of accessors is by default the same as that of properties, but can be changed if desired by placing visibility modifiers before the GET and set keywords. For example, in the following example, we change the visibility of setters to private:
The running results are as follows:
END
1. Follow and reply to Kotlin backstage, and send high-quality learning resources
2. Age: 43
Kotlin concept comb (1) | foundation knowledge view
Kotlin knowledge comb (2) | function definition and calls
Still looking for reasons not to write a tech blog? There are only four steps to writing a good blog
Thanks for liking or sharing
Have help? Click on the top right
Share it with friends, or forward it to moments
Click “Read the original article” to see more