类定义
使用Java定义一个Person
类,代码如下:
public class Person {
private final String name;
private final int age;
public Person() {
}
...
}
使用Kotlin来定义这个类
class Person {
var name = ""
var age = 0
fun printInfo() {
println("$name's age is $age")
}
}
新建对象代码:
fun main() {
val person = Person()
person.name = "Kotlin"
person.age = 20
person.printInfo()
}
//输出
Kotlin's age is 20
属性field、setter、getter
针对类中定义的每个属性,Kotlin都会产生一个field
,一个getter
,和一个setter
(只读属性没有setter
方法),field
用来存储属性性的数据,无法直接定义field
。Kotlin会封装field
,保护里面的数据,只暴露给getter
和setter
使用。
Kotlin会提供默认的getter
和setter
方法,在需要的时候,也可以重新自定义getter
和setter
方法。代码如下:
class Person {
//属性必须赋值除非是可空类型
var nickName: String? = null
var age = 0
var name = ""
set(value) {
field = value.trim()
}
get() = field.capitalize()
}
对于可空属性的空判断使用
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")
}
}
}
关于标准库函数的使用可以看下Kotlin学习 - Kotlin中的标准函数let、with、run、apply、also,看下使用代码:
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
类继承
反编译下上面的Kotlin代码
public final class Person {
@NotNull
private final String name;
...
}
Person类前有final
修饰符,也就是默不可以被继承,而且有public
修饰符,Kotlin的默认访问修饰符就是public
。
如果我们声明一个新的类想继承Person,就需要借助open
关键字。只需在Person类前加上open
:
open class Person {
var name = ""
var age = 0
fun printInfo() {
println("$name's age is $age")
}
}
再反编译下:
public class Person {
@NotNull
private final String name;
...
}
final
修饰符没了,新建一个Student类继承Person,代码如下:
class Student : Person(){
...
}
类构造
1、主构造:直接写在类后面,有点像函数的入参,例如上面定义的Person类修改如下。
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")
}
}
上面的定义中,关键字constructor
表示开始构造函数的声明,如果主构造方法没有访问修饰符或注解,可以去掉该关键字。
init
引入一个初始化语句块,在类创建的时候执行。
构造函数中可以定义个临时变量,然后在给属性进行赋值,例如:_name
为临时变量,内部给成员属性name
进行赋值。和Java中的this.name = _name
一个意思。也可以直接在构造方法中定义属性,例如:val age: Int
。下面是去掉关键字constructor
后的代码:
open class Person (_name: String, val age: Int) {
val name: String
init{
this.name = _name.capitalize()
}
fun printInfo() {
println("$name 's age is $age")
}
}
由于修改了Person的构造函数,此时Student 报错,因为之前使用的是Person无参构造,上面我们修改了Person的构造,则不存在无参构造了。修改代码如下:
class Student(name: String, age: Int, val nickName: String, val grade: Int) : Person(name, age){
...
}
2、次构造
任何一个类只能有一个主构造,但是可以有多个次构造。当一个类既有主构造又有次构造函数时,所有的次构造函数都要调用主构造。
定义构造函数的时候还可以给构造函数指定默认值,当用户调用不提供值参的时候,就使用默认值,代码如下:
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) {
}
...
}
使用方式:
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、无主构造
若类不使用主构造,则后续继承类也不需要使用构造即可去掉继承类的()
,次构造可以调用父类构造super
进行初始化,但是次构造的参数在其他地方无法引用。
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) 报红
}
}
初始化块
1、init
初始化块
在上面Person 类中,出现了一个init
修饰的代码块,这个看起来和Java中的静态代码块很像,其实他们用法差异很大:
- Java中的static表示的是静态代码块,在类加载的时候就会执行,不是在对象创建的时候执行
- Kotlin中初始化代码块会在构造类实例的时候执行,即在对象创建的时候执行
初始化代码块作用:可以设置变量或值,及执行有效性检查,例如检查传给某构造函数的值是否有效,看下例子:
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")
}
}
上面代码就是对构造函数的传入值进行判断,并抛出异常。
2、初始化顺序
属性可以在主构造、次构造、init代码块中执行,那么他们的执行顺序是怎么样的呢:
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")
}
}
将上面代码转为Java字节码候在反编译,看下:
//主构造函数
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);
}
从上面看,有两个构造方法,在次构造中又调用了主构造函数,因此执行顺序是:
1、先赋值的是age
,也就是主构造函数中声明的属性
2、然后是类属性name
3、执行init代码块中属性赋值和函数调用
4、次构造函数中的属性赋值和函数调用
参考博客:文章来源:https://www.toymoban.com/news/detail-495493.html
Kotlin基础学习-入门篇文章来源地址https://www.toymoban.com/news/detail-495493.html
到了这里,关于Kotlin学习 - 类和对象的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!