一、面向对象基础知识
1.1、面向对象案例
Kotlin的类申明,默认是final和public的,Kotlin类、接口修饰符:
- public:默认修饰符,被其修饰的在任何位置都能访问
- private:表示只在这个类(以及它的所有成员)之内可以访问
- protected:在当前类及其子类内访问
- internal:在同一模块内使用
val a = Rect()
println(a.height)//100
println(a.width)//100
val b = Girl()
println(b.name)//张三
println(b.age)//18
b.shopping()//去购物
// 矩形
class Rect {
//静态属性
var height: Int = 100
var width: Int = 100
}
// 妹子
class Girl {
//静态属性
var name: String = "张三"
var age: Int = 18
//动态行为
fun shopping() {
println("去购物")
}
}
1.2、get和set
val修饰的变量是没有set方法的, 也不允许重写set方法。
fun main(args: Array<String>) {
val person = Person()
//person.age=20 //val修饰的变量是没有set方法的, 也不允许重写set方法
println("姓名:${person.name},年龄:${person.age}")//姓名:张三,年龄:18
}
//koltin字段是私有的 会自动生成get和set方法 可以直接访问
class Person{
var name:String="张三"
val age:Int=18 //val修饰的变量是没有set方法的, 也不允许重写set方法
}
1.3、访问器
fun main(args: Array<String>) {
val person = Person2()
// person.name="11"//私有了set方法 不可修改
println("姓名:${person.name},年龄:${person.age}")//姓名:张三,年龄:18
}
//private set 私有了set方法 只能访问 不可修改
class Person2 {
var name: String = "张三"
private set //私有了set方法
var age: Int = 18
}
1.4、自定义访问器
fun main(args: Array<String>) {
val person = Person3()
person.age=120
println("姓名:${person.name},年龄:${person.age}")//姓名:张三,年龄:120
person.age=160
println("姓名:${person.name},年龄:${person.age}")//姓名:张三,年龄:120
}
class Person3 {
var name: String = "张三"
private set //私有了set方法
var age: Int = 18
//自定义访问器
set(value) {
if (value < 150) {
//使用field 修改 age 此时的field相当于this.age
field = value
}
}
}
field的用法,field被大神们翻译成Backing Fields(后端变量),它的作用就类似于java里的this.属性名,例如上面代码中field = value, 就相当于java里的 this.age = value,但是不能直接使用this.age,会造成递归调用内存溢出的, 因为在set和get中是不允许有本身的局部变量的(例如如果你属性名是age, 在set/get里是不能有这个变量的), 因为属性的调用也涉及到了set/get会造成递归调用, 所以要解决引用自身的问题, kotlin发明了field(后端变量)来解决这个问题。注意不是set/get里不允许有局部变量,是不允许有和属性本身相同名字的局部变量。
1.5、构造函数
Kotlin的构造函数,分为主构造函数和次构造函数。
fun main(args: Array<String>) {
val person4 = Person4("张三", 18)
}
//创建的时候就需要修改里面的name和age
//class Person4 constructor(name: String, age: Int) {
//}
//主构造函数没有注解或可见性修饰符,constructor可去除
class Person4 (name: String, age: Int) {
}
1.6、构造函数参数的使用
因为kotlin中的类定义同时也是构造函数,这个时候是不能进行操作的,所以kotlin增加了一个新的关键字init
用来处理类的初始化问题,init模块中的内容可以直接使用构造函数的参数。
fun main(args: Array<String>) {
val person5 = Person5("张三", 99)
println("姓名:${person5.name},年龄:${person5.age}")//姓名:张三,年龄:99
}
//创建的时候就需要修改里面的name和age
class Person5(name: String, age: Int) {
var name:String?=null
var age:Int=0
init {
//构造函数中写的代码可以放到init中执行
this.name=name
this.age=age
}
}
1.7、构造函数参数使用var和val
没有使用var
和val
声明的主构造函数需要手动赋值才可使用
//var add = Add("11", "22")
//println(add.value2)//访问报错
//class Add(value1: String, value2: String)
var add = Add("11", "22")
println(add.value2)//22
class Add(value1: String, value2: String){
var value1:String
var value2:String
init {
this.value1=value1
this.value2=value2
}
}
使用了var
和val
声明的主构造函数中参数,外部可以直接通过 对象.参数
来访问
fun main(args: Array<String>) {
val person6 = Person6("张三", 99)
// person6.age=1//不可修改
println("姓名:${person6.name},年龄:${person6.age}")//姓名:张三,年龄:99
val person7 = Person7("张三", 91)
person7.age=1//可修改
println("姓名:${person7.name},年龄:${person7.age}")//姓名:张三,年龄:1
}
//创建的时候就需要修改里面的name和age, val 相当于final 修饰 不可修改属性
class Person6(val name: String, val age: Int)
//创建的时候就需要修改里面的name和age,var 可修改属性
class Person7(var name: String, var age: Int)
1.8、次构函数
次级构造函数用constructor
加上参数,后面用this
赋值给主构造函数的参数,同时次级构造函数中可以进行代码操作,所以没有init
模块
fun main(args: Array<String>) {
val per = Per("张三", 18, 1)
println("姓名:${per.name},年龄:${per.age},性别:${if (per.sax == 1) "男" else "女"}")//姓名:张三,年龄:18,性别:男
val per2 = Per("李四", 18)
println("姓名:${per2.name},年龄:${per2.age},性别:${if (per2.sax == 1) "男" else "女"}")//姓名:李四,年龄:18,性别:女
}
class Per(var name: String, var age: Int) {
var sax: Int = 0
//constructor次构函数 :this 赋值给主构造函数的参数
constructor(name: String, age: Int, sax: Int) : this(name, age) {
this.sax = sax
}
}
1.9、init和次构执行顺序
类被初始化时,先执行 init
方法后执行主构造函数方法。
fun main(args: Array<String>) {
val per2 = Per2("张三", 18, 1)
//打印结果:调用了init方法 调用了constructor方法
}
class Per2(name: String, age: Int) {
var name: String = ""
var age: Int = 0
var sax: Int = 0
init {
println("调用了init方法")
this.name = name
this.age = age
}
constructor(name: String, age: Int, sax: Int) : this(name, age) {
println("调用了constructor方法")
this.sax = sax
}
}
二、封装
封装:将相应的属性、行为装到一个类中,然后将所有属性私有化。
fun main(args: Array<String>) {
//买一个洗衣机
val machine = WashMachine("海尔",12)
//打开洗衣机门
machine.openDoor()
//放入衣服
println("放入牛仔裤")
//关闭洗洗衣机门
machine.closeDoor()
//设置模式
machine.mode = 1
//点击开始洗衣服按钮
machine.start()
// machine.setMotorSpeed(10000)//转速调节归洗衣机自生所有,不提供给外部调用
}
// 洗衣机
class WashMachine(var brand: String, var l: Int) {
var mode= 0//默认模式 1 轻柔 2 狂揉
//开门动作
fun openDoor(){
println("打开洗衣机门...")
}
//关闭洗衣机门
fun closeDoor() {
println("关闭洗衣机门...")
}
//调节转速操作(不提供给用户,使用private私有化)
private fun setMotorSpeed(speed:Int){
println("当前转速为$speed")
}
//设置模式(用户调节模式)
fun selectMode(mode: Int) {
this.mode = mode
}
//开始洗衣服的按钮
fun start() {
when (mode) {
0 -> {
println("请选择模式")
}
1 -> {
println("开始放水...")
println("水放满了...")
println("开始洗衣服...")
println("洗衣服模式为轻柔")
setMotorSpeed(500)
println("衣服洗好了...")
}
2 -> {
println("开始放水...")
println("水放满了...")
println("开始洗衣服...")
println("洗衣服模式为狂柔")
setMotorSpeed(10000)
println("衣服洗好了...")
}
else->{
println("模式设置错误")
}
}
}
}
三、继承
Kotlin中使用 :
来继承 ,一个类可继承只可继承一个类(单继承),Java中类和方法默认是open的,而Kotlin中默认都是final的,类和方法可以被继承需要open
关键字来修饰,继承方法必须使用override
标识。 否则和父类可以被继承的方法同名,编译器将报错。Kotlin中使用override
修饰符是强制要求的,这样会避免先写出实现方法再添加抽象方法造成的意外重写。
Kotlin中所有类都继承Any
默认提供equals()
、hashCode()
、toString()
fun main(args: Array<String>) {
val son = Son()
son.horbe()
}
/**
* 父亲类
* Kotlin中 默认类都是final 的不可继承,需要增加open关键字 才可以继承
*/
open class Father {
//静态属性
open var name: String = "张三"
open var age: Int = 45
//动态行为
open fun horbe() {
println("父亲喜欢抽烟")
}
}
//孩子类 继承自父亲
class Son : Father() {
//继承父亲属性
override var name: String="张四"
override var age: Int=1
override fun horbe() {
// super.horbe()
println("孩子喜欢抽烟")
}
}
四、抽象类
使用abstract
来修饰表示抽象类,kotlin中方法和属性都可以为抽象。
fun main(args: Array<String>) {
val zhHuman = ZHHuman()
val color = zhHuman.color
val language = zhHuman.language
println("皮肤颜色:$color,使用语言:$language")//皮肤颜色:黄色,使用语言:中文
}
//人类(抽象类)
abstract class Human {
//肤色属性
abstract var color: String
//语言属性
abstract var language: String
//吃饭行为
abstract fun eat()
}
//中国人(继承人类抽象类) open 用于其他类继承
open class ZHHuman : Human() {
override var color: String = "黄色"
override var language: String = "中文"
override fun eat() {
println("使用筷子吃饭")
}
}
//美国人(继承人类抽象类)
class USHuman : Human() {
override var color: String = "白色"
override var language: String = "英文"
override fun eat() {
println("使用刀叉吃饭")
}
}
五、接口
5.1、接口定义
Kotlin中使用 :
来实现接口,多个接口使用,
隔开,一个类可实现多个接口(多实现),实现接口中方法必须使用override
标识, 否则编译器将报错。
fun main(args: Array<String>) {
val xiaoMing = XiaoMing()
xiaoMing.ride()//小明学会了骑自行车
xiaoMing.drive()//小明学会了开车
}
//小明 继承中国人 实现骑车、开车接口
class XiaoMing : ZHHuman(), RideBike, DriveCar {
override fun drive() {
println("小明学会了开车")
}
override fun ride() {
println("小明学会了骑自行车")
}
}
//骑车接口
interface RideBike {
//骑车行为
fun ride()
}
//开车接口
interface DriveCar {
//开车行为
fun drive()
}
5.2、接口细节
Kotlin中接口可以包含属性申明,kotlin 接口中方法也可以有一个默认实现,有默认实现的方法接口被使用,可以直接使用默认实现,可以不用再次重写此方法,当然也可以被重写,使用super.方法名
来调用默认实现。
fun main(args: Array<String>) {
val xiaoFang = XiaoFang("12345678")
xiaoFang.drive()
//打印结果:
// 出示驾照12345678
// 挂挡 踩油门 走
// 小方学会了开车
}
//小方 继承中国人 实现骑车、开车接口
class XiaoFang(override var license: String) : ZHHuman(), RideBikeNew, DriveCarNew {
override fun drive() {
super.drive()
println("小方学会了开车")
}
override fun ride() {
println("小方小学会了骑自行车")
}
}
//骑车接口
interface RideBikeNew {
//骑车行为
fun ride()
}
/**
* 开车接口,Kotlin 接口中字段不可实现(赋值),只能实现类赋值,Java中可以
* Java 接口中方法不可实现,Kotlin中可以
*/
interface DriveCarNew {
//驾照号码
var license: String
//开车行为
fun drive() {
println("出示驾照${license}")
println("挂挡 踩油门 走")
}
}
如果一个类实现了两个接口中相同的方法,可以使用super<接口名>.方法名
来调用接口中默认实现。
interface A {
fun foo() { print("A") }
fun bar()
}
interface B {
fun foo() { print("B") }
fun bar() { print("bar") }
}
class C : A, B {
override fun foo() {
super<A>.foo()
super<B>.foo()
}
override fun bar() {
super<B>.bar()
}
}
六、多态
多态:同一种功能多种表现形式
fun main(args: Array<String>) {
// 多态特点:通过父类接收 执行的是子类的方法
val dog:Animal = Dog("黑色")
println("毛发颜色:${dog.color},动态行为:${dog.call()}")//毛发颜色:黑色,动态行为:狗汪汪叫
val cat:Animal = Cat("白色")
println("毛发颜色:${cat.color},动态行为:${cat.call()}")//毛发颜色:白色,动态行为:猫喵喵叫
}
//动物抽象类
abstract class Animal {
//静态属性 毛发颜色
abstract var color: String
//动态行为
abstract fun call():String
}
//狗 实体类
class Dog(override var color: String) : Animal() {
override fun call(): String{
return "狗汪汪叫"
}
}
//猫 实体类
class Cat(override var color: String) :Animal(){
override fun call():String {
return "猫喵喵叫"
}
}