类与面向对象编程
从面向过程到面向对象,再到设计模式,架构设计,面向服务,Sass、Pass和Iass等思想,各种软
件理论思想五花八门,但万变不离其宗:你要解决一个什么样的问题?
你的问题是哪个领域的?
你的模型(数据结构)是什么?
你的算法是什么?
你对这个世界的本质认知是怎样的?
你的业务领域的逻辑问题、流程是什么?
声明类
1. 空类
2. 声明类和构造函数
class People(var id: Int) {
var age: Int = 0; // 没有延迟初始化的必须声明的时候初始化
lateinit var name: String; // 延迟初始化
// 二级构造器必须调用主构造器
// 构造器中参数不能使用val或者var声明
constructor(id: Int, age: Int, name: String) : this(id) {
this.age = age
this.name = name
}
// 重写toString方法
override fun toString(): String {
return "People(id=$id, age=$age, name='$name')"
}
}
fun main() {
val people = People(42119999) // 调用主构造器
people.age = 20 // 类中属性默认是public,在其他包中也可以访问
people.name = "kris"
}
当子类继承了某个类之后,便可以使用父类中的成员变量,但并不是完全继承父类的所有成员变量。具体的原则如下:
- 能够继承父类的public和protected成员变量;
- 不能继承父类的private成员变量;
- 对于父类的包访问权限成员变量,如果子类和父类在同一个包下,则子类能够继承;否则,子类不能继承;
- 对于子类可以继承的父类成员变量,如果在子类中出现了同名称的成员变量,则会发生隐藏现象,即子类的成员变量会屏蔽掉父类的同名成员变量。如果要在子类中访问父类中的同名成员变量,需要使用super关键字进行引用。
3 Object对象
Kotlin中没有静态对象,需要实现单例模式,可以使用Object单例对象
object User{
var id = "admin"
var pw = "admin"
override fun toString(): String {
return "$id + $pw"
}
}
fun main() {
println(User) // admin + admin
}
或者使用伴生对象
class DBClient(var id : Int){
fun open(){
println("DBClient id $id")
openDB()
}
// 伴生对象,一个类只有一个
companion object DBEngine{
fun openDB(){
println("DB engine open db")
}
}
}
fun main() {
DBClient(1).open()
DBClient(2).open()
}
/*
DBClient id 1
DB engine open db
DBClient id 2
DB engine open db
*/
4. 数据类
//主构造器不能为空
data class Music(var id : Int){
lateinit var name : String;
}
这是Kotlin的数据类,可以反编译一下,查看对应的Java代码
public final class Music {
@NotNull
public String name; // 在类中声明的变量是public的
private int id; // 主构造器中变量式私有的,也就是说不能继承
// 构造器
public Music(int id) {
this.id = id;
}
// ============= get and set fun
// get&set 都是被声明为final,不能重写
@NotNull
public final String getName() {
String var10000 = this.name;
if (var10000 == null) {
Intrinsics.throwUninitializedPropertyAccessException("name");
}
return var10000;
}
public final void setName(@NotNull String var1) {
Intrinsics.checkParameterIsNotNull(var1, "<set-?>");
this.name = var1;
}
public final int getId() {
return this.id;
}
public final void setId(int var1) {
this.id = var1;
}
//===============
// component1 返回主构造器中下表为1的属性值
public final int component1() {
return this.id;
}
// 拷贝函数
@NotNull
public final Music copy(int id) {
return new Music(id);
}
// $FF: synthetic method
@NotNull
public static Music copy$default(Music var0, int var1, int var2, Object var3) {
if ((var2 & 1) != 0) {
var1 = var0.id;
}
return var0.copy(var1);
}
// 只包含主构造器中的域
@NotNull
public String toString() {
return "Music(id=" + this.id + ")";
}
// 只包含主构造器中的域
public int hashCode() {
return this.id;
}
// 只包含主构造器中的域
public boolean equals(@Nullable Object var1) {
if (this != var1) {
if (var1 instanceof Music) {
Music var2 = (Music)var1;
if (this.id == var2.id) {
return true;
}
}
return false;
} else {
return true;
}
}
}
- 主构造函数至少包含一个参数;
- 参数必须标识为val或者var;
- 不能为abstract、open、sealed或者inner;
- 不能继承其他类(但可以实现接口)。
- 可以在解构声明中使用
Pair
Kotlin中提供了二元组Pair,和三元组Triple,可以使用Pair实现Map
public data class Pair<out A, out B>(
public val first: A,
public val second: B
) : Serializable {
public override fun toString(): String = "($first, $second)"
}
/**
* Creates a tuple of type [Pair] from this and [that].
*
* This can be useful for creating [Map] literals with less noise, for example:
* @sample samples.collections.Maps.Instantiation.mapFromPairs
*/
public infix fun <A, B> A.to(that: B): Pair<A, B> = Pair(this, that)
// 重写了中缀表达式to
使用Pair实现Map
fun main() {
val map = mapOf(1 to 'A', 2 to 'B', 3 to 'C')
println(map) // 创建的是LinkedHashMap类型的Map
}
// mapOf方法在 kotlin.collections包中(默认导入)
public fun <K, V> mapOf(vararg pairs: Pair<K, V>): Map<K, V> =
if (pairs.size > 0) pairs.toMap(LinkedHashMap(mapCapacity(pairs.size))) else emptyMap()
内部类
1.普通内部类
一个类可以嵌套其他类中,并且可以嵌套多层,普通内部类不持有外部类的引用,所以不能访问外部类属性。
class Out{
var v = 1
class inner{
fun cout(){
println(v) // Error
}
}
}
2.嵌套内部类
如果需要在内部类中获取外部类的this指针,可以使用嵌套内部类
class Out{
var v = 1
inner class inner{
fun cout(){
println(v) // OK
}
}
}
3.匿名内部类
匿名内部类也可以访问外部类属性。匿名内部类最经典的运用场景应该就是创建子线程
class MyThread {
// 匿名内部类实现
fun doRun1() {
Thread(object : Runnable {
override fun run() {
println(Thread.currentThread().id)
}
}).start()
}
// Lambda表达式实现
fun doRun2() {
Thread(Runnable {
println(Thread.currentThread().id)
}).start()
}
//使用lambda表达式和匿名内部类
fun doRun3() {
val run = Runnable {
println(Thread.currentThread().id)
}
Thread(run).start()
}
// 直接使用lambda表达式
fun doRun4() {
val run = {
println(Thread.currentThread().id)
}
Thread(run).start()
}
}
fun main() {
println(Thread.currentThread().id) // 1
MyThread().doRun1() // 12
MyThread().doRun2() // 13
MyThread().doRun3() // 14
MyThread().doRun4() // 15
}
方法4和方法2其实是一样的。方法1和方法3其实是一样的。