-
继承与重载的关键字open
类默认都是封闭的,要想某个类开放继承,必须使用open关键字修饰它
在main函数中调用
//继承
val carProduct : Product = CarProduct()
println(carProduct.description())
println(carProduct.load())
//继承
open class Product(val name : String){
fun description () = "Product === $name"
open fun load () = "Loading..."
}
//继承父类,父类必须用open关键字,否则默认类是final
class CarProduct:Product("aodi"){
//这里的override是关键字,重写某父类方法需要加override,并且父类方法必须声明为open
override fun load () ="aodi Loading..."
fun carMethod() = "car special Method"
}
-
类型转换
is as 关键字
kotlin中的Any超类,类似于java中的object
//类型转换
println(carProduct is Product)
println(carProduct is CarProduct)
if(carProduct is CarProduct){
println((carProduct as CarProduct).carMethod())
}
-
对象声明
使用object关键字,可以定义一个只能产生一个实例的类--单例
使用object关键字有三种方式
1.对象声明
//在kotlin中,声明一个类为单例很方便,直接使用object
object ApplicationConfig{
init {
println("applicationConfig init...")
}
fun doSomething(){
println("doSomething")
}
}
在main函数中调用
//在kotlin中,声明一个类为单例很方便,直接使用object
ApplicationConfig.doSomething()//这里并不是说是静态的,而是声明了是单例类,这里就可以直接使用类名作为对象名
//指向的都是同一个对象,因为它是单例
println(ApplicationConfig)
println(ApplicationConfig)
println(ApplicationConfig)
2.对象表达式
open class Player8 {
open fun load() = "loading nothing"
}
在main函数中调用
//对象表达式作为子类
//类似于java中的new 一个OnclickListener,这个匿名类依然遵循object关键字的原则,一旦实例化,只能有唯一一个实例存在
val p = object : Player8(){
override fun load() = "匿名类的loading方法"
}
println(p.load())
3.伴生对象
//伴生对象
open class SinggleTest{
//只有初始化SinggleTest类或者调用load函数时,伴生对象的内容才会载入
//而且无论实例化多少次,这个伴生对象始终只有一个实例存在。有点类似java的static
//一个类里只能有一个伴生对象
companion object{
private const val PATH = "xxxxxxx"
fun load() = println("伴生对象的方法执行")
}
}
在main函数中调用
//伴生对象
SinggleTest.load()
- 嵌套类
//嵌套类(内部类)
//如果一个类只对另一个类有用,那么将其嵌入到该类中并使两个类保持在一起就很合逻辑,可以使用嵌套类
class Player1{
class Equipment(var name:String){
fun show() = println("equipment:$name")
}
fun battle() = println("ak47...")
}
在main函数中调用
//嵌套类(内部类)
Player1.Equipment("天空套").show()
-
数据类
专门用来存储数据的类
看源码可以看到,默认实现了toString方法,打印的时属性值
==符合默认情况下,在any超类里面比较的是它们的引用值,数据类提供了equals和hashcode的个性化实现,比较的是内容
/**
* 使用数据类的条件
* 对于那些经常需要比较,复制或打印自身内容的类,数据类很适用。然而,一个类要成为数据类,也要符合一定条件,总结下来,主要有三个方面
* 1.数据类必须有至少带一个参数的主构造函数
* 2.数据类主构造函数的参数必须是var 或者 val
* 3.数据类不能使用abstract,open,sealed和inner修饰符
*/
//数据类,用data关键字修饰
data class Coordinate(val x : Int,val y : Int){
}
在main函数中调用
//这里打印的是Coordinate(x=1, y=2)。如果不用data修饰,打印的是Coordinate@60e53b93
println(Coordinate(1,2))
//这里结果是true,如果类名不用data修饰,则是false
println(Coordinate(1,2) == Coordinate(1,2))
- copy函数
//data数据类的copy函数demo
data class StudentOrigin(
val name: String,
var age : Int,
var isNormal : Boolean
){
var score = 0
//次构造函数,有主就有次,我们可以定义多个次构造函数来配置不同的参数组合
constructor(_name: String) : this (_name,age = 10,isNormal = false){
//copy函数不会调用这,copy出去的值还是0
score = 10
}
//初始化块,与java的static不一样,这里的初始化块是构造函数执行的时候,就会执行初始化快
init {
//先决函数,如果boolean值是false,执行lambda抛出异常
require(age > 0) {
"age must be positive"
}
require(name.isNotBlank()){
"student must have a name"
}
}
override fun toString(): String {
return "StudentOrigin(name='$name', age=$age, isNormal=$isNormal, score=$score)"
}
}
在main函数中调用
//copy函数,它可以将数据类的其他属性都copy过来。但是这里有一个坑,次构造函数里面修改过的值不能copy,需要重新赋值
val s = StudentOrigin("Jack")
val copy = s.copy("Rose")
println(s)
println(copy)
- 解构声明
//解构语法的demo类
class Demo(val x:Int , val y : Int){
//这里的component1等名字都是固定写法,不能修改
operator fun component1() = x
operator fun component2() = y
}
//数据类,用data关键字修饰
data class Coordinate(val x : Int,val y : Int){
}
在main函数中调用
//数据类默认支持解构语法,如果不是数据类,则需要我们手动在类里面重写方法,就如果解构语法demo类一样。
val (x,y) = Coordinate(1,2)
println("$x,$y")
//解构语法的demo类
val (a,b) = Demo(3,4)
println("$a,$b")
-
运算符重载
使用operator关键字
/**
* 运算符重载,常见的操作符
*
*
* 操作符 函数名 作用
* + plus 把一个对象添加到另一个对象里
* += plusAssign 把一个对象添加到另一个对象里,然后将结果赋值给第一个对象
* == equals 如果两个对象相等,则返回true,否则返回false
* > compareTo 如果左边的对象大于右边的对象,就返回true,否则返回false
* [] get 返回集合中指定位置的元素
* .. rangeTo 创建一个range对象
* in contains 如果对象包含在集合里,则返回true
*
*/
data class Coordinate2(val x: Int,val y: Int){
//运算符重载,使用operator关键字
operator fun plus(other:Coordinate2) = Coordinate2(x+other.x,y+other.y)
}
在main函数中调用
//运算符重载
val coordinate2 = Coordinate2(10,50)
val coordinate3 = Coordinate2(20,100)
//如果下面的运算符不重写,这里使用+号就会报错
println(coordinate2+coordinate3)
-
枚举类
枚举类也可以定义函数
data class Coordinate2(val x: Int,val y: Int){
//运算符重载,使用operator关键字
operator fun plus(other:Coordinate2) = Coordinate2(x+other.x,y+other.y)
}
//枚举类,也可以定义函数
enum class Direction(val coordinate:Coordinate2){
EAST(Coordinate2(1,2)),
WEST(Coordinate2(3,4)),
NORTH(Coordinate2(5,6)),
SOUTH(Coordinate2(7,8));
fun updateCoordinate(other: Coordinate2) = Coordinate2(
other.x + coordinate.x,
other.y + coordinate.y
)
}
在main函数中调用
//枚举类,用来定义常量集合的一种特殊类
println(Direction.EAST) //输出的就是枚举的字符串值
println(Direction.WEST.updateCoordinate(Coordinate2(10,20)))
-
密封类
密封类(sealed),从枚举类思考更复杂的需求,比如我需要控制其中一个对象具有某种属性,这时候使用密封类,但不要混淆,密封类不是枚举
密封类可以用来定义一个类似于枚举类的类型,但是可以更灵活的控制某个子类型
密封类可以有若干个子类,要继承密封类,这些子类必须和它定义在同一个文件中
//密封类demo
class Driver(var status: LicenseStatus){
fun checkLicense () : String {
return when(status){
is LicenseStatus.Unqualified -> "没资格"
is LicenseStatus.Learning -> "正在学"
is LicenseStatus.Qualified -> "有资格,驾驶证编号: " + (this.status as LicenseStatus.Qualified).licenseId
}
}
}
//密封类
sealed class LicenseStatus{
object Unqualified : LicenseStatus() //这里没有属性,所以把它定义为单例
object Learning : LicenseStatus() //这里没有属性,所以把它定义为单例
class Qualified (var licenseId:String) : LicenseStatus() //这里有一个id的属性,所以不定义为单例
}
在main函数中调用
println(Driver(LicenseStatus.Qualified("2820202")).checkLicense())
println(Driver(LicenseStatus.Learning).checkLicense())
网友评论