Android Kotlin(1)之《类》
大家好!这是我第三篇文章,之前说Toast例子先欠着哈,等我发完Kotlin系列后继续更新,最后有我的源码,欢迎关注和下载,源码也会逐渐完善。这也是我学习Kotlin后写的第一篇文章,在网上查找很多资料和自己也实验很多,后续我会陆续发布相应Kotlin其他文章,欢迎大家多多支持,我就不介绍相关环境搭建了,这个环境搭建还是很简单的,Android studio有插件支持的,只需要配置好Gradle就好,我就直接正对Kotlin进入使用介绍,第一个要介绍的就是《类》。当然我写的也许不全面,你也可以提出遗漏的,我们大家一起补充完善。
类和继承
1、类(Class)
java类文件:XXX.java
Kotlin类文件:XXX.kt
Kotlin 中使用关键字 class 声明类
class ClassGoKotlin {
}
类声明由类名、类头(指定其类型参数、主构造函数等)和由大括号包围的类体构成。类头和类体都是可选的; 如果一个类没有类体,可以省略花括号。
class ClassGoKotlin
与java区别:都是Class申明,只是java默认是有public,当然java也可以省去public,但是java不可以像Kotlin去掉类的“{}”大括号,主要区别在于构造函数和初始化,如下:
构造函数
在 Kotlin 中的一个类可以有一个主构造函数和一个或多个次构造函数。主构造函数是类头的一部分:它跟在类名(和可选的类型参数)后。
class ClassGoKotlin constructor(param1 : String){
}
如果主构造函数没有任何注解或者可见性修饰符,可以省略这个 constructor 关键字。
class ClassGoKotlin(param1 : String) {
}
主构造函数特性:
1、主构造函数不能包含任何的代码,初始化在init关键字里作为前缀的初始化模块里,例如:
class ClassGoKotlin(param0 : String) {
var param1 : String? = param0.toUpperCase()
init {
//主构造函数初始化
this.param1 = param0.toUpperCase()
}
2、主构造函数可以声明属性以及初始化属性,在主构造函数参数前家var或者val就是声明属性,在参数后面可以附上默认的初始值,例如:
class ClassGoKotlin(var param0 : String, var param00 : String = "赋默认初始值") {
var param1 : String? = param0.toUpperCase()
init {
//主构造函数初始化
this.param1 = param0.toUpperCase()
}
特别说明:赋有默认值的参数,在调用该类的时候可以不填写该参数,不填写该参数,Kotlin会自动按照默认参数执行
3、如果构造函数有注解或可见性修饰符,这个 constructor 关键字是必需的,并且这些修饰符在它前面,如果没有注解或者可见性修饰符,主构造函数constructor 可以省略,例如:
class Customer public @Inject ClassGoKotlin(name: String) { …… }
4、唯一性,一个类里只有一个主构造函数,
次构造函数特性:
1、次构造函数必须有constructor前缀声明
2、如果类有一个主构造函数,每个次构造函数需要委托给主构造函数。委托到同一个类的另一个构造函数用 this 关键字即可,例如:
class ClassGoKotlin(param0 : String,var param00 : String = "赋默认初始值") {
var param1 : String? = param0.toUpperCase()
init {
//主构造函数初始化
this.param1 = param0.toUpperCase()
}
//每个次构造函数需要委托给主构造函数
constructor(param1: String,classGoKotlin: ClassGoKotlin) : this(param1){
this.param1 = param1.toUpperCase()
}
}
3、可以直接委托或者通过别的次构造函数间接委托,例如:
//每个次构造函数需要委托给主构造函数
constructor(param1: String,classGoKotlin: ClassGoKotlin) : this(param1){
this.param1 = param1.toUpperCase()
}
//每个次构造函数也可以委托给其他次造函数
constructor(param1: String, param2 : String , classGoKotlin: ClassGoKotlin) : this(param1,classGoKotlin) {
this.param2 = param2
}
特别说明:如果一个非抽象类没有声明任何(主或次)构造函数,它会有一个生成的不带参数的主构造函数。如果你不想你的类有一个公有的构造函数,你可以声明一个私有的主函数
class ClassGoKotlin private constructor () {
}
与java区别:java是不允许在Class这行里添加参数,java类默认是default(默认访问模式,只允许在同一个包中进行访问),Kotlin默认是public(公有的);java里不存在主次构造函数,但是委托还是有的,也是this实现的在代码里实现,例如:
//java
public class ClassGoJava{
public ClassGoJava(){
}
public ClassGoJava(String param1){
this();
}
public ClassGoJava(String param1, String param2){
this(param1);
}
}
创建类实例
直接上例子:
class ClassGoKotlin(param0 : String,var param00 : String = "赋默认初始值") {
var param1 : String? = param0.toUpperCase()
var param2 : String? = null
var param3 : String? = null
init {
//主构造函数初始化
this.param1 = param0.toUpperCase()
}
//每个次构造函数需要委托给主构造函数
constructor(param1: String,classGoKotlin: ClassGoKotlin) : this(param1){
this.param1 = param1.toUpperCase()
}
//每个次构造函数也可以委托给其他次造函数
constructor(param1: String, param2 : String , classGoKotlin: ClassGoKotlin) : this(param1,classGoKotlin) {
this.param2 = param2
}
constructor(param1: String, param2 : String ,param3 : String , classGoKotlin: ClassGoKotlin) : this(param1,param2,classGoKotlin){
this.param2 = param2
}
constructor(param1: String, param2 : String ,param3 : String ,param4 : String, classGoKotlin: ClassGoKotlin) : this(param1,param2,param3,classGoKotlin){
this.param3 = param3
}
}
创建:
var classGoKotlin0 = ClassGoKotlin("0")
var classGoKotlin00 = ClassGoKotlin("0","可有可以无参数,看需求")
var classGoKotlin1 = ClassGoKotlin("1", "2","4",ClassGoKotlin("0"))
var classGoKotlin2 = ClassGoKotlin("1", "2","3","4",ClassGoKotlin("0"))
var classGoKotlin3 = ClassGoKotlin("1", "2","3","4",ClassGoKotlin("1","2",ClassGoKotlin("0")))
...等等,灵活使用,建议还是不要太复杂,前三个就好,委托多了容易乱
与java区别:Kotlin没有new关键字,比Java更加简洁
2、继承
在 Kotlin 中所有类都有一个共同的超类 Any,这对于没有超类型声明的类是默认超类:
class Example // 从 Any 隐式继承
被继承的类前必须要加open关键字,才被允许继承。如果该类有一个主构造函数,其基类型可以(并且必须) 用(基类型的)主构造函数参数就地初始化例如:
open class ClassGoKotlin(param0 : String,var param00 : String = "赋默认初始值") {}
class ClassGoKotlinEx : ClassGoKotlin(""){}
如果类没有主构造函数,那么每个次构造函数必须使用 super 关键字初始化其基类型,或委托给另一个构造函数做到这一点。 注意,在这种情况下,不同的次构造函数可以调用基类型的不同的构造函数:
class ClassGoKotlinEx : ClassGoKotlin{
//必须至少要有一个次构造函数,否则要在上面继承的时候就ClassGoKotlin("必须实现")
constructor(param0 : String) : super(param0){
//这个就是ClassGoKotlinEx(""),因为没有主构造函数,这个就类似主构造函数
}
constructor() : super("这里固定好值"){
//这个就是ClassGoKotlinEx(""),因为没有主构造函数,这个就类似主构造函数
}
//这样就可以传递参数到继承的类里了
constructor(param1 : String, classGoKotlinEx: ClassGoKotlinEx) : super(param1) {
//经过我实际测试,这个次构造函数必须基于上面的构造函数才可以实现,否则ClassGoKotlinEx("", ClassGoKotlinEx());这样是不能调用的
}
//这个和上面第二个实际上是一样的,没有区别,可以删除
constructor(classGoKotlinEx: ClassGoKotlinEx) : this(){
}
}
使用上面的基础类:
//传入自定义数据
var a = ClassGoKotlinEx("测试", ClassGoKotlinEx());
//不传入数据,使用ClassGoKotlinEx类里设好的固定数据
var b = ClassGoKotlinEx();
覆盖方法
Kotlin类覆盖继承类的方法,这里要求必须清晰,所有被继承的类如果需要被覆写,需要加上open关键字标识,就和需要继承的类需要加上open;所有被重写的方法需要override关键字标识,这样我们就非常的清晰那些类可以基础,那些方法可以覆盖,增强的可可读性,比java可读性强,例如:
//被继承类里声明方法
fun v(){}
open fun nv(){}
//继承类里覆盖方法
override fun nv(){}
Kotlin中,如果你想已经继承类的覆盖发放不在被再次覆盖的话,你只需要在覆盖方法前加final关键字即可,例如:
final override fun nv(){}
覆盖属性
和覆盖方法一样。
特别注意的是:
可以用一个 var 属性覆盖一个 val 属性,但反之则不行。这是允许的,因为一个 val 属性本质上声明了一个 getter 方法,而将其覆盖为 var 只是在子类中额外声明一个 setter 方法。
你可以在主构造函数中使用 override 关键字作为属性声明的一部分
覆盖规则
在 Kotlin 中,实现继承由下述规则规定:如果一个类从它的直接超类继承相同成员的多个实现, 它必须覆盖这个成员并提供其自己的实现(也许用继承来的其中之一)。 为了表示采用从哪个超类型继承的实现,我们使用由尖括号中超类型名限定的 super,如 super<Base>:
//类继承,方法覆盖规则
open class A {
open fun f() {}
fun a() {}
}
interface B {
fun f() {} // 接口成员默认就是“open”的
fun b() {}
}
class C() : A(), B {
// 编译器要求覆盖 f():
override fun f() {
super<A>.f() // 调用 A.f()
super<B>.f() // 调用 B.f()
}
}
同时继承 A 和 B 没问题,并且 a() 和 b() 也没问题因为 C 只继承了每个函数的一个实现。 但是 f() 由 C 继承了两个实现,所以我们必须在 C 中覆盖 f() 并且提供我们自己的实现来消除歧义。
抽象类
类和其中的某些成员可以声明为 abstract。 抽象成员在本类中可以不用实现。 需要注意的是,我们并不需要用 open 标注一个抽象类或者函数——因为这不言而喻。+
我们可以用一个抽象成员覆盖一个非抽象的开放成员
//抽象类
open class Base {
open fun f() {}
}
abstract class Derived : Base() {
override abstract fun f()
}
同伴对象(Companion Object)
Koltin没有静态方法(static method),可以使用同伴对象代替,就实现了类似java静态方法的功能,只是这里同伴对象关键字大括号内所有方法都是同伴对象,类似java静态方法,例如:
//同伴对象(Companion Object)
companion object {
//companion object静态方法集合关键字
fun Test1(): String? {
return ""
}
}
封闭类
封闭类用来表示对类阶层的限制,可以限定一个值只允许是某些指定的类型之一,而不允许是其他类型。
要声明一个封闭类,需要将 sealed 修饰符放在类名之前,封闭类可以有子类,但所有的子类声明明都必须嵌套在封闭类的声明部分之内。
sealed class Expr {
class Const(val number: Double) : Expr()
class Sum(val e1: Expr, val e2: Expr) : Expr()
object NotANumber : Expr()
}
从封闭类的子类再继承的子类(间接继承者)可以放在任何地方,不必在封闭类的声明部分之内。
好了,第一期就到这了,谢谢大家的观赏,敬请期待下一期《函数和Lambda表达式》
源码下载
这里源码会随着后面发布的Kotlin逐渐完善