热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Android—Kotiln基础教程(五)

前言在上一篇中主要讲解了Kotlin关于集合相关的知识点,在本篇中,将会对Kotlin的对象进行详解!1.对象1.1示例一(无构造函

前言

在上一篇中主要讲解了Kotlin关于集合相关的知识点,在本篇中,将会对Kotlin的对象进行详解!


1. 对象


1.1 示例一(无构造函数)

class Player {//分析点1var name = "abc"get() = field.capitalize()set(value) {field = value.trim()}var age = 10 get() = field.absoluteValueprivate set(value) { field = value.absoluteValue}val rolledValue//取随机数get() = (1 until 6).shuffled().first()var words: String? = null //分析点2fun saySomeThine() { //分析点3words?.also { "Hello ${it.toUpperCase()}" }.run(::println)}
}
fun main{var player = Player()player.name = "tom"//player.age=-10 //因为set被改成私有,所以这里报错player.words="main hello" println(player.name)println(player.age)println(player.rolledValue)player.saySomeThine()
}

定义了一个对象,里面有对应的成员属性。注意看这里面的分析点:


  • 分析点1:分别实现了对应的get、set方法,并且在对应的方法里实现了对应的逻辑。
  • 分析点2:该成员变量并没有任何get、set方法
  • 分析点3:在方法saySomeThine里,对成员属性使用了.also关键字,最后再打印

运行效果:

Tom
10
4
main hello

从这个运行效果可以看到:对象里的成员,就算不实现对应的get、set方法,并且在没有使用private情况下,在外部依旧可以调用对应的get、set方法


1.2 示例二(有主构造函数)

// ----------------初始化
class Player1(_name: String,_age: Int,_isNormal: Boolean) {var name = _nameget() = field.toLowerCase()private set(value) {field = value.trim()}private var age = _agevar isNormal = _isNormalfun playerInfo() {//println(_name) //会报错println("name: $name; age:$age ;isNormal $isNormal")}
}fun main() {var player = Player1("Tom", 20, true)player.playerInfo()}

运行效果

name: tom; age:20 ;isNormal true

从这段代码看,这个Player1应该是一个拥有有参构造方法的对象。而对应的_name、_age、_isNormal,就是对应构造方法里的构造参数,有效期也仅在对应的构造方法里。


1.3 示例三(有主次构造函数)

class Player2(_name: String,var age: Int = 12, //执行顺序 1var isNormal: Boolean) {var name = _name //执行顺序2get() = field.capitalize()private set(value) {field = value.trim()}fun playerInfo() {println("name: $name; age:$age ;isNormal $isNormal")}//次构造函数【】 这里的this()相当于执行了主构造函数 相当于顺序1和2constructor(name: String) : this(name, age = 100, isNormal = false ) {this.name = name.toUpperCase()println("constructor----------")//执行顺序 4}init { // 执行顺序3//初始化代码块 会在构造类实例时执行// 则可以 在这进行 数值的检查 满足条件则抛出异常println("init----------")require(age > 10) { println("age must be positive") }require(name.isNotBlank()) { println("player must have a name") }}
}fun main() {var player2=Player2("Tom", 20, true)player2.playerInfo()var player3 = Player2("bob", isNormal = false)player3.playerInfo()var player4=Player2("hqk")player4.playerInfo()
}

运行效果:

init----------
name: Tom; age:15 ;isNormal true
init----------
name: Bob; age:12 ;isNormal false
init----------
constructor----------
name: HQK; age:100 ;isNormal false

这次在代码里面加入了constructor以及init,constructor的意思就是创建一个次构造函数;而init相当于java里面的static代码块。里面对应的执行顺序在注释里标注清楚了。

init代码块里含有require方法,这里面的意思就是:当里面的表达式不成立/false时,将直接报错,自定义错误信息就在后面闭包里实现。


1.4 示例四(延迟初始化)

class Player3 {lateinit var equipment: Stringfun ready() {equipment = "sharp knife"}fun battle() {if (::equipment.isInitialized) println(equipment)}
}fun main{var palyer3 = Player3()palyer3.ready() //必须 调用该方法 才能使用对应的属性变量palyer3.battle()
}

运行效果:

sharp knife

在之前的学习中,我们认知到,当我们定义变量的时候,要么一开始赋初始值,要么通过.?表明这个变量为可空。但在对象的使用里,我既不想一开始赋初始值,也不想让这个变量为可空的,那就只有通过lateinit表明这个属性变量需要在后面初始化(使用它之前)!

那万一在使用它之前未初始化该怎么办呢?岂不是就直接报空指针异常了?Kotlin也提供了对应的解决方案:只要无法确认 lateinit 变量是否完成初始化,可以执行 isInitialized 检查


1.5 示例五(惰性初始化)


class Player4(_name: String) {var name = _nameval config by lazy { loadConfig() }private fun loadConfig(): Boolean {println("loading...")return false}
}fun main{var play4 = Player4("Tom");println(play4.config)
}

运行效果

loading...
false

这里我们看到,当定义成员属性时,使用了by lazy {}的方式,让config实现了惰性初始化。当使用play4.config成员属性时,它才会初始化相应的操作。


1.6 示例六(初始化陷阱)

class Player5() {init {//这样会直接报错blood = this.blood.times(4)}var blood = 100
}

当我们将变量放在init闭包后时,将会发现代码居然报了语法错误。解决方案也很简单,只需要将init闭包放在最后即可。

class Player6() {var blood = 100init {//这样就不会报错blood = this.blood.times(4)}
}fun main{var play6=Player6()println(play6.blood )
}

运行效果:

400

1.7 示例七(对象的继承)

class Player7() {val name: Stringprivate fun firstLetter() = name[0]init {name = "Jack" //分析点1firstLetter()}//--------------继承----------------open class Product(val name: String) { //分析点2open fun description() = "Product: $name"open fun load() = "Nothing..."fun add(num1: Int, num2: Int) = num1 + num2 //该方法不可被子类重写}class LuxuryProduct : Product("Java") {//---重载override fun load() = "Java " + description()}
}
/*** 类型转换*/
fun sale(p: Player7.Product) {println(p.load())
}fun main() {val play7 = Player7()println(play7.name)val product = LuxuryProduct()product.description().run(::println)product.load().run(::println)//类型检测println(product is LuxuryProduct)println(product is Player7.Product)sale(product)sale(product as Player7.Product) //分析点3
}

我们先看这几点分析点:


  • 分析点1:和上面示例一样,当init代码块在对应的属性定义下方时,可在这闭包里初始化对应变量,即使变量是用val修饰的,依然能够初始化。
  • 分析点2:当我们想是用继承时,可以通过open class XXX定义被继承的对象,里面的方法如果想要被子对象重写的话可使用open修饰对应的方法。子类继承父类语法为:class 子类 : 父类
  • 分析点3:当我们想进行对象的转换时,可使用as关键字强转对应的对象。

运行效果

Jack
Product: Java
Java Product: Java
true
true
Java Product: Java
Java Product: Java

结束语

好了,本篇到这里就结束了,本想着在这篇吧对象讲完的,奈何发现内容太丰富了。还有很多很多,加上时间不允许了,还要写那个代码撸猫,所以暂时放到下一篇了。


推荐阅读
author-avatar
零摄氏度玫瑰_460
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有