kotlin从入门到看开 ₅
2018-10-30 本文已影响9人
東方月初
layout: post
title: "kotlin-面向对象"
subtitle: "前途和未卜都未必能够回报我的任性"
面向对象
在Java中有继承 封装 和 多态 那么在Kotlin中自然也是有的.这里不再累述
//继承
class MyDrived() : MyBase() {
override fun method1() {}
}
类及其成员的可见性
Kotlin
-
public : 均可见
-
private : 只用类内部可见
-
protected : 子类可见
-
internal : 模块内可见(model内可见)
object
object这是个什么东西呢?
- 只有一个实例的类
- 不能自定义构造方法
- 可以实现接口,继承父类
- 本质上就是单利模式的最基本实现
class Driver
interface OnExternalDriverMountListener {
fun onMount(driver: Driver)
fun onUnmount(driver: Driver)
}
abstract class Player
object MusicPlayer : Player(), OnExternalDriverMountListener {
override fun onMount(driver: Driver) {}
override fun onUnmount(driver: Driver) {}
val state: Int = 0
fun play(url: String) {}
fun stop() {}
}
伴生对象
- 伴生对象与Java中的静态方法类似
- 每个类可以对应一个伴生对象
- 伴生对象的成员全局只有一份
companion object
Kotlin中使用方式
- 可以通过 类名.函数名 调用函数
- 那么变量 类名.变量名 调用变量
Java中若想调用
- 在函数上加 @JvmStatic 注解
- 在变量上加 @JvmField 注解 既可以正常调用
伴生对象的写法如下:
fun main(args: Array<String>) {
println(Girl.sing("来相思树下"))
println(Girl.TAG)
}
class Girl private constructor() {
companion object {
@JvmStatic
fun sing(song: String): String {
return song
}
@JvmStatic
fun dance(dance: String): String {
return dance
}
@JvmField
val TAG: String = "涂山苏苏"
}
}
幕后字段
kotlin没有显示字段,所有为字段赋值的操作都会调用set方法,对于一些必须要直接赋值的操作提供了幕后字段.
field
var i = 8
set(value) {
println(value)
field=value
}
扩展成员
可以对Java已有的类进行扩展成员
比如我想对String类添加一个方法 对传入字符串打印N次
- 操作符扩展方法 字符串*3
- 普通方法名扩展方法 字符串.times(3)
fun main(args: Array<String>) {
println("lalala" * 3)
println("lalala".times(3))
}
operator fun String.times(time: Int): String {
val stringBuilder = StringBuilder()
for (i in 0 until time) {
stringBuilder.append(this + "\n")
}
return stringBuilder.toString()
}
属性代理
使用方法:
val/var <属性名>:<Type> by <代理对象>
val hello2 by X()//若是可推导出类型可不写
自定义代理时要实现相应的setValue/getValue方法
class Delegates{
val hello by lazy {
"HelloWorld"
}
val hello2 by X()
var hello3 by X()
}
class X{
private var value: String? = null
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
println("getValue: $thisRef -> ${property.name}")
return value?: ""
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String){
println("setValue, $thisRef -> ${property.name} = $value")
this.value = value
}
}
fun main(args: Array<String>) {
val delegates = Delegates()
println(delegates.hello)
println(delegates.hello2)
println(delegates.hello3)
delegates.hello3 = "value of hello3"
println(delegates.hello3)
}
数据类
数据类用data关键字标记
data
data class User(val name: String, val age: Int)
数据类须满足以下要求:
- 主构造函数需要至少有一个参数 ;
- 主构造函数的所有参数需要标记为 val 或 var ;
- 数据类不能是抽象\开放\密封或者内部的;
- 在1.1之前数据类只能实现接口.自 1.1 起,数据类可以扩展其他类(示例请参见密封类).
在 JVM 中,如果生成的类需要含有一个无参的构造函数,则所有的属性必须指定默认值.
data class User(val name: String = "", val age: Int = 0)
补充:
data class 是被final修饰的不可以被继承,而且没有无参构造,这就导致它无法作为javabean使用.官方出了两个插件来解决这个问题.
- Projec gradle添加依赖
dependencies {
classpath"org.jetbrains.kotlin:kotlin-allopen:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-noarg:$kotlin_version"
}
- 创建自己的annotation
package com.littonishir.github.annotation
annotation class Ishir
- Module gradle应用插件
apply plugin: 'kotlin-noarg'
apply plugin: 'kotlin-allopen'
noArg{
annotation("com.littonishir.github.annotation.Ishir")
}
allOpen{
annotation("com.littonishir.github.annotation.Ishir")
}
- 使用自己定义的annotation
package com.littonishir.github
import com.littonishir.github.annotation.Ishir
@Ishir
data class Games(val name: String, val version: String)
我们反编译这个data class Games 来看看真相吧
package com.littonishir.github;
import com.littonishir.github.annotation.Ishir;
import kotlin.Metadata;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;
@Ishir
@Metadata(
mv = {1, 1, 10},
bv = {1, 0, 2},
k = 1
)
//final修饰符已经没有了
public class Games {
@NotNull
private final String name;
@NotNull
private final String version;
@NotNull
public String getName() {
return this.name;
}
@NotNull
public String getVersion() {
return this.version;
}
public Games(@NotNull String name, @NotNull String version) {
Intrinsics.checkParameterIsNotNull(name, "name");
Intrinsics.checkParameterIsNotNull(version, "version");
super();
this.name = name;
this.version = version;
}
@NotNull
public final String component1() {
return this.getName();
}
@NotNull
public final String component2() {
return this.getVersion();
}
@NotNull
public final Games copy(@NotNull String name, @NotNull String version) {
Intrinsics.checkParameterIsNotNull(name, "name");
Intrinsics.checkParameterIsNotNull(version, "version");
return new Games(name, version);
}
// $FF: synthetic method
// $FF: bridge method
@NotNull
public static Games copy$default(Games var0, String var1, String var2, int var3, Object var4) {
if (var4 != null) {
throw new UnsupportedOperationException("Super calls with default arguments not supported in this target, function: copy");
} else {
if ((var3 & 1) != 0) {
var1 = var0.getName();
}
if ((var3 & 2) != 0) {
var2 = var0.getVersion();
}
return var0.copy(var1, var2);
}
}
public String toString() {
return "Games(name=" + this.getName() + ", version=" + this.getVersion() + ")";
}
public int hashCode() {
String var10000 = this.getName();
int var1 = (var10000 != null ? var10000.hashCode() : 0) * 31;
String var10001 = this.getVersion();
return var1 + (var10001 != null ? var10001.hashCode() : 0);
}
public boolean equals(Object var1) {
if (this != var1) {
if (var1 instanceof Games) {
Games var2 = (Games)var1;
if (Intrinsics.areEqual(this.getName(), var2.getName()) && Intrinsics.areEqual(this.getVersion(), var2.getVersion())) {
return true;
}
}
return false;
} else {
return true;
}
}
//无参构造诞生
public Games() {
}
}
内部类
- 定义在类内部的类
- 默认是静态内部类,非静态用inner 关键字标记
inner
open class Outter{
val a: Int = 0
inner class Inner{
val a: Int = 5
fun hello(){
/**
* 静态内部类不持有外部类的引用,不能访问外部类的成员
* 非静态内部类持有外部类的引用,可以访问外部类的成员
*/
println(a)
//完整的写法
println(this@Outter.a)
}
}
}
匿名内部类
- 没有定义名字的内部类
- 类名编译时生成,类似于Outter$1.class
- 可以继承父类实现多个接口,Java不可以继承父类在这里
//匿名内部类的写法
val textView = TextView(this)
textView.setOnClickListener {object : View.OnClickListener {
override fun onClick(view: View?) {
textView.text = "hi"
}
}
}
//lambda的写法
textview.setOnClickListener { textview.text = "hi" }
枚举
- 实例可数的类,注意枚举也是类
- 可以修改构造,添加成员
- 可以提升代码的表现力,也有一定的性能开销
enum
enum class LogLevel(val id: Int) {
VERBOSE(0), DEBUG(1), INFO(2), WARN(3), ERROR(4), ASSERT(5);
fun getTag(): String {
return "$id, $name"
}
override fun toString(): String {
return "$name, $ordinal"
}
}
fun main(args: Array<String>) {
println(LogLevel.DEBUG.ordinal)
LogLevel.values().map(::println)
println(LogLevel.valueOf("ERROR"))
}
密封类
- 子类可数
- 1.1之前子类必须定义在密封类的内部
- 1.1之后子类只需要与密封类在同一个文件中
sealed
sealed class PlayerCmd {
class Play(val url: String, val position: Long = 0): PlayerCmd()
class Seek(val position: Long): PlayerCmd()
object Pause: PlayerCmd()
object Resume: PlayerCmd()
object Stop: PlayerCmd()
}
enum class PlayerState{
IDLE, PAUSE, PLAYING
}