抽象类和接口
接口
- 直观理解就是一种约定,Kotlin的接口与Objective-c的Proticol比较类似
- 不能有状态
- 必须由类对其进行实现后使用
抽象类
- 实现了一部分协议的半成品
- 可以有状态,可以有方法实现
- 必须有子类集成后使用
抽象类和接口的共性
- 比较抽象,不能直接示例化
- 有需要子类(实现类)实现的方法
- 父类(接口)变量可以接受子类(实现类)的示例赋值
抽象类和接口的区别
- 抽象类有状态,接口没有状态
- 抽象类有方法实现,接口只能有无状态的默认实现
- 抽象类只能单继承,接口I可以多实现
- 抽象类反映本质,接口体现能力
继承(实现)语法要点
- 父类需要open才可以被继承(抽象类不需要,生来就是被继承的)
- 父类方法、属性需要open才可以被复写
- 接口、接口方法、抽象类默认为open
- 覆写父类(接口)成员需要override关键字
- class D:A(),B,C
- 注意继承类时实际上是调用了父类构造方法
- 类只能但继承,接口可以多实现
接口代理
interface Driver{
fun drive()
fun abc()
}
class Manager(driver:Driver):Driver by driver
class Manager(driver: Driver):Driver{
override fun drive(){
driver.drive()
}
override fun abc(){
driver.abc()
}
}
接口方法冲突
- 接口方法可以有默认实现
- 签名一致且返回值相同的冲突
- 子类(实现类)必须覆写冲突方法
- super<父类(接口)名>.方法名(参数列表)
类成员的可见性对比
Kotlin |
Java |
private |
private |
protected |
protected |
- |
default(包内可见) |
internal(模块内可见) |
- |
public |
public |
object
- 只有一个实例的类
- 不能自定义构造方法
- 可以实现接口、继承父类
- 本质上就是java中最简单的单例
伴生对象与静态方法
- 每个类可以对应一个半生对象
- 半生对象的成员全局独一份(针对类来说的)
- 半生对象的成员类似java的静态成员
伴生对象与静态成员
- 静态成员考虑用包级函数、变量代替(不依赖于某一个类)
- Java中要调用Kotlin的伴生对象的方法,在Kotlin代码中添加@JvmStatic注解方便调用,调用成员,添加@JvmField
//Kotlin代码
package printlin.net
/**
* @created 2018/11/2 12:06
* @description:
* @author sunxiaxia
*/
fun main(args: Array<String>) {
val a = minOf(args[0].toInt(), args[1].toInt())
val latitude2 = Latitude.ofDouble(5.0)
val latitude = Latitude.ofLatitude(latitude2)
println(latitude.TAG)
}
class Latitude private constructor(val value: Double) {
companion object {
fun ofDouble(double: Double): Latitude {
return Latitude(double)
}
@JvmStatic
fun ofLatitude(latitude: Latitude): Latitude {
return Latitude(latitude.value)
}
}
@JvmField
val TAG:String = "Latitude"
}
//Java代码
public class JavaStatic {
public static void main(String...args){
Latitude latitude = Latitude.Companion.ofDouble(6.0);
Latitude latitude1 = Latitude.ofLatitude(latitude);
System.out.println(latitude1.TAG);
}
}
方法重载和默认参数
- 方法重载(Overloads)
- 名称相同、参数不同的方法
- Jvm函数签名的概念:函数名、参数列表,跟返回值无关
默认函数
- 为函数参数设定一个默认函数
- 可以为任意位置参数设置默认值
- 函数调用产生混淆时用具名参数
方法重载与默认参数
- 二者的相关性以及@JvmOverloads
- 避免定义关系不大的重载
- 不好的设计
//java中
List.remove(int)
List.remove(Object)
//在Kotlin中
List.removeAt()=>List.remove(Int)
List.remove(Object)=>List.remove(Object)
扩展成员
fun X.y():Z{...}
val X.m //注意扩展属性不能初始化,类似接口属性
- java调用扩展成员类似调用静态方法:对应的Kotlin类名Kt.方法名
fun main(args: Array<String>) {
println("hello".multiply(3))
}
fun String.multiply(int:Int):String{
val stringBuilder = StringBuilder()
for (i in 0 until int){
stringBuilder.append(this)
}
return stringBuilder.toString()
}
//Java中调用
ExtendsKt.times("kjhfj",7);
属性代理
//定义方法
val/var name:Type by expression
- 代理者需要实现相应的setValue/getValue方法
- lazy原理剖析
数据类(Data clas,再见JavaBean)
- 默认实现的copy、toString等方法
- componentN方法 ,可以自己写
val (a,b,c) = dataClass实例
例:
val person = Person("张丹",35)
val (a,b) = person
println("姓名:$a,年龄:$b")
- allOpen和noArg插件,解决数据类被final修饰且没有空的构造函数的问题(dataClass是final,从设计角度上不允许有子类,通过allopen插件可是实现在编译期通过字节码的方式将fianl去掉,通过noArg插件可以实现无参构造方法)
group 'cn.onestravel'
version '1.0-SNAPSHOT'
buildscript {
ext.kotlin_version="1.3.0"
repositories {
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-allopen:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-noarg:$kotlin_version"
}
}
apply plugin: 'java'
apply plugin: 'kotlin'
apply plugin: 'kotlin-allopen'
apply plugin: 'kotlin-noarg'
noArg{
annotation("net.println.demo1.DataBean")
}
allOpen{
annotation("net.println.demo1.DataBean")
}
repositories {
mavenCentral()
}
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
}
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
kotlinOptions.jvmTarget = "1.8"
}
内部类
- 定义在类内部的类,默认是静态内部类(java默认的是非静态内部类),非静态用inner关键字,与类成员有相似的访问控制
- 内部类访问外部类的成员用@this@Outter,内部类的成员可以用this@Inner也可以不用。
匿名内部类
- 没有定义名字的内部类
- 类名编译时生成,类似Outter@1.class
- 可以继承父类、实现多个接口(Java不能同时继承父类又实现接口,要么继承一个类,要么实现一个接口)
枚举(enmu)
- 实例可数的类,注意枚举也是类
- 可以修改构造,添加成员
- 可以提升代码的表现力,也有一定的性能开销
密封类(sealed)
- 子类可数(枚举是实例可数)
- Kotlin v1.1之前子类必须定义在密封类的内部类
- v1.1后,子类只需要与密封类在同一个文件中
-
网友评论