构造方法
fun main() {
//次构造方法创建对象
val student = Student()
println(student.toString())
student.age = 23
student.name = "jim"
student.flag = true
println(student.toString())
//主构造方法创建对象
val student2 = Student("main", 18, true)
println(student2.toString())
//具名主构造函数创建对象(需要少传的参数提前给好默认值)
val student3 = Student("main20", flag = true)
println(student3.toString())
//初始化代码块发现年龄小于等于0时抛出异常
val student4 = Student("age0", -1, false)
println(student4.toString())
}
//主构构造方法 构造方法中可以直接设置成员变量,系统自动为其生成get和set方法
//只使用一次的临时变量前面加_
//代码初始化执行顺序:1主构造函数赋值,2类中成员变量赋值和初始化代码块运行取决于谁写在前面,3次构造函数运行
class Student(_name:String, var age:Int = 20, var flag:Boolean) {
//自定义get set方法
var name:String? = _name
get() = field?.toUpperCase()
set(value) {
field = "姓名:$value"
}
//次构造方法
constructor() : this("AaA", 22, false){
//TODO 次构造方法中初始化
}
//初始化代码块,构造函数调用时调用
//初始代码块若要使用类中成员的变量,必须把使用类中成员变量的赋值写在初始代码块上面
init {
require(age > 0) {"年龄不能小于等于0"}
}
override fun toString(): String {
return "姓名:${name},年龄${age},标识:${flag}"
}
//延迟初始化属性使用关键字lateinit,使用前需要手动初始化才能使用
lateinit var late:String
fun initLate() {
late = "late"
}
fun useLate() {
//判断是否被初始化,不判断未初始化会报UninitializedPropertyAccessException
if (::late.isInitialized){
println(late)
}
}
//惰性初始化属性使用关键字by lazy,表示第一次使用时自动初始化为后面的值
val config by lazy {"config"}
}
继承
fun main() {
val a = A()
//B构造时构造方法与A的次级构造相同,所以走父类次级构造方法
val b:A = B()
//is判断关键字进行类型判断
println(a is A)//true
println(a is B)//false
println(a is File)//false
println(b is A)//true
println(b is B)//true
println(b is File)//false
//as关键字进行向下类型转换
(b as B).inputChild()
//kotlin智能类型转换,只要前面转换成功,后续使用该对象可以不用转换直接使用
b.inputChild()
//Any是所有类的父类,相当于java的Object
//与Object不同的是Any中并不能直接看到方法的实现,方法会根据不同的环境变换实现内容,比java跨平台性更强大
println(a is Any)
}
//kotlin默认都是不可继承的,用open关键字表示可继承
open class A(open var name:String) {
constructor() : this("p") {
input()
}
open fun input() = println("Parent,${name}")
}
class B : A() {
//override关键字表示重写父类方法
override fun input() = println("Child,${name}")
fun inputChild() = println("only child can use")
}
object关键字
fun main() {
val s1 = Single
val s2 = Single
println(s1 === s2)//true
//调用方法直接使用类名
Single.pri()
//生成一个单例类型的SingleP匿名子类
val c = object : SingleP() {
override fun pri() {
println("SingleC")
}
}
c.pri()
//伴生对象调用
SingleComp.load()
SingleComp.path = "path2"
SingleComp.load()
}
//object修饰的为单例对象,不可有构造方法
object Single {
fun pri() {
println("Single")
}
}
open class SingleP {
open fun pri() {
println("SingleP")
}
}
class SingleComp {
//kotlin中没有static关键字
//companion object表示类中的伴生对象,只有外界调用时才会加载进内存,且内存中一直保持为一份
companion object {
private const val CONFIG = "config"
var path = "path"
fun load() = println(CONFIG + path)
}
}
嵌套类
fun main() {
Outer().outer()
//和java不一样,kotlin可以外部类可以用类名直接创建内部类并进行调用方法
Outer.Inner().inner()
}
class Outer {
class Inner {
fun inner() = println("Inner")
}
fun outer() = println("Outer")
}
数据类
fun main() {
println(WH(1, 2))//打印内存地址
//数据类系统默认重写了toString方法打印数据内容
println(XY(1, 2))//打印数据内容
//==比较的是equals
println(WH(1, 2) == WH(1, 2))
//数据类重写了equals方法和hashCode方法
println(XY(1, 2) == XY(1, 2))
val xy = XY(1)
//copy函数拷贝数据类,拷贝过程不走次构造函数,只拷贝主构造函数的数据
val xyC = xy.copy(x = 50)
println(xy)//x=1,y=888,z=999
println(xyC)//x=50,y=888,z=10
//普通类实现解构语法
val(a, b) = WH(2, 3)
println("a=${a},b=${b}")
//数据类中自动生成解构语法声明,可直接使用
val(c, d) = XY(10, 20)
println("c=${c},d=${d}")
//使用运算符重载
println(XY(11, 22) + XY(33, 55))
}
//普通类
class WH(var w:Int, var h:Int) {
//普通类实现解构语法需要先声明
operator fun component1() = w
operator fun component2() = h
}
//数据类使用data关键字
//需要比较,复制打印自身内容的时候使用数据类比较好
//数据类必须有至少带一个参数的主构造函数,且主构造函数参数必须用val和var修饰
//数据类不能用abstract,open,sealed,inner修饰
data class XY(var x:Int, var y:Int) {
var z:Int = 10
constructor(_x:Int) : this(_x, 2) {
z = 999
y = 888
println("次构造函数")
}
//运算符重载
//+ plus
//+= plusAssign
//== equals
//> compareTo
//[] get
//.. rangeTo
//in contains
operator fun plus(other:XY) = XY(other.x + x, other.y + y)
override fun toString(): String {
return "x=${x},y=${y},z=${z}"
}
}
枚举
fun main() {
println(Direction.EAST)
//枚举元素就是枚举类的一个实例对象
println(Direction.EAST is Direction)
//枚举中方法使用
println(Direction.WEST.getXY(XY(12, 14)))
//枚举配合选择语句使用
val dir = Direction.NORTH
println(when(dir) {
Direction.EAST -> "东"
Direction.WEST -> "西"
Direction.SOUTH -> "南"
Direction.NORTH -> "北"
})
}
//枚举中可以有方法,枚举对象可以有构造属性
enum class Direction(private val xy:XY) {
EAST(XY(1, 1)),
WEST(XY(2, 2)),
SOUTH(XY(3, 3)),
NORTH(XY(4, 4));
fun getXY(pXY:XY) = XY(pXY.x + xy.x, pXY.y + xy.y)
}
密封类
fun main() {
val abc:ABC = when((1..3).random()) {
1 -> ABC.A
2 -> ABC.B
3 -> ABC.C("ccc")
else -> ABC.A
}
println(when(abc){
is ABC.A -> "a"
is ABC.B -> "b"
is ABC.C -> (abc as ABC.C).cId
})
}
//密封类,类似枚举的实现,包含一系类继承自己的子类
sealed class ABC {
//没有属性的子类使用单例节省内存
object A : ABC()
object B : ABC()
//有属性的子类使用class做出区分
class C(val cId:String) : ABC()
}