Kotlin学习 - 类和对象

这篇具有很好参考价值的文章主要介绍了Kotlin学习 - 类和对象。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

类定义

使用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,保护里面的数据,只暴露给gettersetter使用。

Kotlin会提供默认的gettersetter方法,在需要的时候,也可以重新自定义gettersetter方法。代码如下:

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、次构造函数中的属性赋值和函数调用

参考博客:

Kotlin基础学习-入门篇文章来源地址https://www.toymoban.com/news/detail-495493.html

到了这里,关于Kotlin学习 - 类和对象的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 18:kotlin 类和对象 -- 数据类(Data classes)

    数据类是其主要目的是保存数据的类。数据类会自动附带额外的成员方法 使用 data 声明一个数据类 编译器会自动从 主构造函数 中声明的所有属性派生以下成员 .equals() / .hashCode() .toString() 如: \\\"User(name=John, age=42)\\\" .componentN() (在后边的文章会讲到) .copy() 为了确保生成的代码

    2024年02月03日
    浏览(48)
  • 23:kotlin类和对象 -- 内联值类(Inline value classes)

    有时,将一个值包装在一个类中可以创建一个更具领域特定类型的类。然而,由于额外的堆分配,这会引入运行时开销。此外,如果包装的类型是原始类型,性能损失是显著的,因为原始类型通常由运行时进行了大量优化,而它们的包装类没有得到任何特殊处理。 为了解决这

    2024年02月03日
    浏览(43)
  • Scala第六章节(类和对象的定义、访问修饰符和构造器的用法、main方法的实现形式、伴生对象的使用以及工具类的案例)

    章节目标 掌握类和对象的定义 掌握访问修饰符和构造器的用法 掌握main方法的实现形式 掌握伴生对象的使用 掌握定义工具类的案例 1. 类和对象 Scala是一种函数式的面向对象语言, 它也是支持面向对象编程思想的,也有类和对象的概念。我们依然可以基于Scala语言来开发面向

    2024年03月19日
    浏览(46)
  • jvm中类和对象定义存储基础知识

    Class文件结构主要有两种数据结构: 无符号数和表 • 无符号数 :用来表述数字,索引引用、数量值以及字符串等,比如 图1中类型为u1,u2,u4,u8分别代表1个字节,2个字节,4个字节,8个字节的无符号数 • 表 :表是有由多个无符号数以及其它的表组成的复合结构,比如图1中类

    2024年02月08日
    浏览(51)
  • 类和对象(上)--关于面向对象,类的定义,访问限定符,this指针

    二次修订于date:2024:3:6 C语言是一们面向过程的语言,关注的是函数执行的过程,数据和方法是分离的。 C++是一门面向对象的语言,主要关注对象,将一件事情抽象成不同的对象,靠对象间的交互来完成。对象与对象之间的交互叫做消息(举例外卖系统中,分为快递小哥,

    2024年03月21日
    浏览(52)
  • JPA使用nativeQuery自定义SQL怎么插入一个对象参数呢?

    0、我们在前后端传递数据时候,参数多的情况下,常常将这些参数封装成对象;当有些场景你需要使用JPA nativeQuery自定义SQL,要将这个对象insert时候,初学者似乎有点犯难,jpa不是spring-data项目的内容吗,所以在sql中也是支持SPEL表达式来获取参数,运用这个思路可以继续 1、

    2024年02月14日
    浏览(40)
  • c++学习——类和对象

    类是自定义数据类型,是C语言的结构体进化而成的 对象是类实例化出的,用数据类型定义一个变量 C和C++中struct区别: C语言struct只有变量 C++语言struct既有变量,也有函数 1、为什么要有封装? 封装是把属性(变量)和方法(函数)封装到类内,然后给这些数据赋予权限,防

    2024年02月07日
    浏览(36)
  • 【C++学习】类和对象(上)

    前言: 由于之前电脑“嗝屁”了,导致这之前一直没有更新博客,今天才拿到电脑,在这里说声抱歉。接下来就进入今天的学习,在之前我们已经对【C++】进行了初步的认识,有了之前的知识铺垫,今天我们将来带领大家学习我们【C++】中的一个重要知识,即“ 类和对象 ”

    2023年04月10日
    浏览(31)
  • C++学习:类和对象(上)

    这是C++这样的面向对象的语言具有的特性,相较于C语言来说,更加方便的去编写代码,调用代码。 当需要大量重复的调用同一个函数的时候,我们每创建一个函数,就会建立一个栈帧,这样对于空间来讲不友好,C语言中有宏函数这样的函数,来解决这一问题,下面是宏函数

    2023年04月23日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包