1. 面向对象
1.1 创建一个类 + 构造方法说明
class TestCons constructor() {
}
kotlin采用 constructor 关键字来代表构造方法,其中的 constructor 可以省略,但是如果加上权限修饰符就不能省略了:
class TestCons constructor() {
}
// 有参构造
class TestCons constructor(age:Int, name:String) {
}
// 如果加上权限 private 修饰符,就不能省略 关键字 constructor了
class TestCons private constructor(age:Int, name:String) {
}
如果是 无参构造函数,可以省略 constructor()。那么如果想在构造方法中做一些参数初始化,该如何进行呢,就需要用到 init 代码块了。
init 代码块 的执行顺序在构造方法之后,如下所示:
class TestCons {
var name:String = ""
var age:Int = 0
init {
name = "zhangsan"
age = 10
}
}
1.2 带参构造函数 及 初始化
class TestCons(name: String, age: Int) {
var name: String = ""
var age: Int = 0
init {
this.name = name
this.age = age
}
fun print() {
println("TestCons name = $name, age=$age")
}
}
// 测试类
var test = TestCons("zhangsan", 20)
test.print()
// 输出
TestCons name = zhangsan, age=20
这种带参构造函数,然后还需要在 init 代码块中初始化的方式是不是很麻烦,kotlin提供了另外一种简单的方式:
class TestCons(val name: String, val age: Int) {
fun print() {
println("TestCons name = $name, age=$age")
}
}
// 测试类
var test = TestCons("zhangsan", 20)
test.print()
// 输出
TestCons name = zhangsan, age=20
在构造方法中,将两个参数前面添加 val 或者 var 关键字,将其作为本类中的变量,输出结果一样。
1.3 主构造函数 和 次构造函数
java模式:
package compare.java;
public class Rect2 {
private int length;
private int width;
public Rect2() {
}
public Rect2(int length, int width) {
this.length = length;
this.width = width;
}
public void smile() {
System.out.println("java length = " + length);
}
}
kotlin模式:
package compare.kt
class Rect2() { // 主构造函数
private var length = 0
private var width = 0
constructor(length: Int, width: Int) : this() { // this就是主构造函数
this.length = length
this.width = width
}
fun smile() {
println("rect2 smaile length = $length")
}
}
测试类:
package compare
fun main(args: Array<String>) {
var rect1 = compare.kt.Rect2(20, 20)
var rect2 = compare.kt.Rect2()
var rec3 = compare.java.Rect2()
var rec4 = compare.java.Rect2(20, 20)
}
在java中并没有主次构造方法的区别,但是Kotlin中有主次构造方法
1. 跟随在class 之后的就是主构造方法
2. 主构造方法只能有一个,次构造方法可以有多个
3. 如果从次构造函数进来,之后还要再走一次主构造函数
2. 抽象类 和 多态
2.1 抽象类
/**
* 创建抽象类
*/
abstract class Human(name: String) {
abstract fun eat()
}
// 实现抽象类
class Man(name: String) : Human(name) {
override fun eat() {
println("man eat")
}
}
2.2 继承 + 重写 + 父类引用指向子类对象
open 关键字:
1. 父类在class前使用,才可以使其子类能继承
2. 子类重写父类的方法,父类方法前需要添加才能重写
// 子类
class Son : Father() {
override fun action() {
println("father do action")
}
}
// 父类
open class Father() {
var character = "性格内向"
open fun action() {
println("father do action")
}
}
// 测试类
fun main(args: Array<String>) {
var father: Father = Son()
father.action()
}
3. 接口
3.1 接口
interface IMan {
fun eat()
}
class Man2:IMan {
override fun eat() {
println("eat food")
}
}
3.2 接口和抽象类区别
在使用的时候,抽象类需要:带个括号,而接口直接写就可。
class Man3(name: String) : Human(name), IMan {
override fun eat() {
}
override fun eat2() {
}
}
/**
* 创建抽象类
*/
abstract class Human(name: String) {
abstract fun eat()
}
interface IMan {
fun eat2()
}
4. 委托 ,代理和单例
by 关键字:将洗碗的操作 委托给BigHeadSon,调用 SmallHeadFather.washing时会执行到BigHeadSon的washing方法
class SmallHeadFather : IWashBall by BigHeadSon() {
}
class BigHeadSon : IWashBall {
override fun washing() {
println("BigHeadSon washing")
}
}
interface IWashBall {
fun washing()
}
// 测试方法
fun main(args: Array<String>) {
var smallHeadFather = SmallHeadFather()
smallHeadFather.washing()
}
4.1 变形一
在委托前后还可以做一些其他的事情。
class SmallHeadFather : IWashBall by BigHeadSon() {
override fun washing() {
println("委托前可以做一些事情")
BigHeadSon().washing()
println("委托后也可以做一些事情")
}
}
如果这样的话 by 关键之之后的 BigHeadSon(),以及 调用washing方法的 BigHeadSon(),会分别创建一个对象,这样会造成对象的 内存空间的浪费。
4.2 变形二
object 关键字:被修饰的类已经在jvm内存中创建了一个实例,有且只有一个,就是单例类。
使用的时候就可以不用带括号,直接类名即可。
object BigHeadSon : IWashBall {
override fun washing() {
println("BigHeadSon washing")
}
}
class SmallHeadFather : IWashBall by BigHeadSon {
override fun washing() {
println("委托前可以做一些事情")
BigHeadSon.washing()
println("委托后也可以做一些事情")
}
}
5. 静态类 和 静态方法
5.1 静态类
使用 object 关键字修饰的即为静态类。
object StaticUtil{
fun method()
...
5.2 普通类中的静态方法
companion object 关键字:大括号里面的都是静态的。
class StaticUtils {
companion object { // 包裹范围内 属于静态方法,静态属性
val TAG = "lbs" // 定义常量
fun method()
...
}
}