class definition
Define a Person
class using Java, the code is as follows:
public class Person {
private final String name;
private final int age;
public Person() {
}
...
}
Use Kotlin to define this class
class Person {
var name = ""
var age = 0
fun printInfo() {
println("$name's age is $age")
}
}
New object code:
fun main() {
val person = Person()
person.name = "Kotlin"
person.age = 20
person.printInfo()
}
//输出
Kotlin's age is 20
Attribute field, setter, getter
For each attribute defined in the class, Kotlin will generate one field
, one getter
, and one setter
(read-only attributes have no setter
methods), field
which are used to store attribute data and cannot be directly defined field
. Kotlin will encapsulate field
, protect the data inside, and only expose getter
and setter
use it.
Kotlin will provide default getter
and methods, and methods can be re - setter
defined when needed . code show as below:getter
setter
class Person {
//属性必须赋值除非是可空类型
var nickName: String? = null
var age = 0
var name = ""
set(value) {
field = value.trim()
}
get() = field.capitalize()
}
For the null judgment of nullable attributes, use
class Person {
//属性必须赋值除非是可空类型
var nickName: String? = null
var age = 0
var name = ""
set(value) {
field = value.trim()
}
get() = field.capitalize()
//如果一个函数即可变又可为空,可以在使用前使用also或者let进行判空处理
fun printHello() {
nickName?.also {
println("also - hello $it")
}
nickName?.let {
print("let - hello $it")
}
}
}
For the use of standard library functions, you can look at Kotlin Learning - the standard functions let, with, run, apply, and also in Kotlin , and see the usage code:
fun main() {
var p = Person()
p.name = "Lucky"
println(p.name)
p.name = " tom"
println(p.name)
p.nickName = "kk"
p.printHello()
}
//运行结果
Lucky
Tom
also - hello kk
let - hello kk
class inheritance
Decompile the Kotlin code above
public final class Person {
@NotNull
private final String name;
...
}
There is a modifier before the Person class final
, that is, it cannot be inherited silently, and there are public
modifiers, Kotlin's default access modifier is public
.
If we declare a new class that wants to inherit Person, we need to use open
keywords. Just prefix the Person class with open
:
open class Person {
var name = ""
var age = 0
fun printInfo() {
println("$name's age is $age")
}
}
Then decompile:
public class Person {
@NotNull
private final String name;
...
}
final
The modifier is gone, create a new Student class to inherit Person, the code is as follows:
class Student : Person(){
...
}
class structure
1. Main structure: write directly after the class, which is a bit like the input parameter of a function. For example, the Person class defined above is modified as follows.
open class Person constructor(_name: String, val age: Int) {
val name: String
init{
this.name = _name.capitalize()
}
fun printInfo() {
println("$name 's age is $age")
}
}
In the above definition, the keyword constructor
indicates the declaration of the beginning constructor. If the main constructor has no access modifier or annotation , the keyword can be removed.
init
Introduce an initialization statement block that is executed when the class is created.
A temporary variable can be defined in the constructor, and then assign values to attributes, for example: as a temporary variable, internally assign values _name
to member attributes . name
and a meaning in Java this.name = _name
. Properties can also be defined directly in the constructor, for example: val age: Int
. Here is constructor
the code after removing the keywords:
open class Person (_name: String, val age: Int) {
val name: String
init{
this.name = _name.capitalize()
}
fun printInfo() {
println("$name 's age is $age")
}
}
Because the constructor of Person has been modified, Student reports an error at this time, because the Person no-argument construction was used before, and we have modified the Person construction above, so there is no no-argument construction. Modify the code as follows:
class Student(name: String, age: Int, val nickName: String, val grade: Int) : Person(name, age){
...
}
2. Secondary construction
Any class can only have one main construction, but can have multiple secondary constructions. When a class has both primary and secondary constructors, all secondary constructors must call the primary constructor.
When defining the constructor, you can also specify a default value for the constructor. When the user calls without providing a value parameter, the default value will be used. The code is as follows:
class Student(name: String, age: Int, val nickName: String, val grade: Int) : Person(name, age){
constructor(name: String, age: Int, nickName: String) : this(name, age, nickName, 8) {
}
constructor() : this("Default", 12, "Default", 8) {
}
...
}
How to use:
fun main() {
val student1 = Student("lucky", 20, "luck", 9)
val student2 = Student("Joice", 20, "joo")
val student3 = Student()
println("${
student1.name} + ${
student1.nickName} + ${
student1.age} + ${
student1.grade}")
println("${
student2.name} + ${
student2.nickName} + ${
student2.age} + ${
student2.grade}")
println("${
student3.name} + ${
student3.nickName} + ${
student3.age} + ${
student3.grade}")
}
//运行结果:
Lucky + luck + 20 + 9
Joice + joo + 20 + 8
Default + Default + 12 + 8
3. Ownerless structure
If the class does not use the primary structure, the subsequent inherited class does not need to use the structure to remove the inherited class ()
. The secondary structure can call the parent class structure super
for initialization, but the parameters of the secondary structure cannot be referenced elsewhere.
open class Person {
var name: String = ""
var age: Int = 0
constructor(_name: String, _age: Int) {
this.name = _name
this.age = _age
}
}
class Student : Person {
constructor(name: String, age: Int, nickName: String) : super(name, age) {
}
fun study() {
//name,age可使用
println(name + "is studying")
//使用nickName则会报错,若nickName是主构造的参数则可引用
//println(nickName) 报红
}
}
initialization block
1. init
Initialization block
init
In the above Person class, a modified code block appears , which looks very similar to the static code block in Java, but their usage is quite different:
- The static in Java means a static code block, which will be executed when the class is loaded, not when the object is created
- The initialization code block in Kotlin will be executed when the class instance is constructed, that is, executed when the object is created
The function of the initialization code block: you can set variables or values, and perform validity checks, such as checking whether the value passed to a constructor is valid, see the following example:
open class Person (_name: String, val age: Int) {
var name = _name;
init{
require(age > 0){
"age must be positive"}
require(name.isNotBlank()){
"person must be have a name"}
}
fun printInfo() {
println("$name 's age is $age")
}
}
The above code is to judge the incoming value of the constructor and throw an exception.
2. Initialization sequence
Attributes can be executed in primary construction, secondary construction, and init code block, so what is their execution order:
open class Person (_name: String, val age: Int) {
var name = _name;
constructor() : this("Default", 12) {
println("执行次构造函数")
}
init{
println("执行init")
require(age > 0){
"age must be positive"}
require(name.isNotBlank()){
"person must be have a name"}
}
fun printInfo() {
println("$name 's age is $age")
}
}
Convert the above code into Java bytecode and wait for decompilation, see:
//主构造函数
public Person(@NotNull String _name, int age) {
Intrinsics.checkNotNullParameter(_name, "_name");
super();
this.age = age;
this.name = _name;
String var3 = "执行init";
boolean var4 = false;
System.out.println(var3);
boolean var7 = this.age > 0;
var4 = false;
boolean var5 = false;
boolean var6;
String var9;
if (!var7) {
var6 = false;
var9 = "age must be positive";
throw (Throwable)(new IllegalArgumentException(var9.toString()));
} else {
CharSequence var8 = (CharSequence)this.name;
var4 = false;
var7 = !StringsKt.isBlank(var8);
var4 = false;
var5 = false;
if (!var7) {
var6 = false;
var9 = "person must be have a name";
throw (Throwable)(new IllegalArgumentException(var9.toString()));
}
}
}
//次构造函数
public Person() {
this("Default", 12);
String var1 = "执行次构造函数";
boolean var2 = false;
System.out.println(var1);
}
From the above, there are two construction methods, and the main constructor is called in the secondary construction, so the execution order is:
1. The first assignment is age
the attribute declared in the main constructor
2, and then the class attributename
3. Execute attribute assignment and function call in the init code block
4. Attribute assignment and function call in the secondary constructor
Reference blog: