类的声明
在kotlin中用class
声明类
class InClass{}
类的声明包括类名,类头(指定参数类型,主构造函数等等),以及类主体,一般用大括号包裹,类头和类体是可以选的,如果没有类体可以省略大括号,如下
class Empty
构造函数
在kotlin中,类可以有一个主构造函数以及多个二级构造函数
,主构造函数是类头的一部分;跟在类名后面且可以有可选的类型参数
class Student constructor(name:String)
如果没有主构造函数,没有注解或者可见性说明,则constructor
关键字可以省略,写成下面这样
class Student (name:String){}
主构造函数不能包含任意代码,初始化代码可以放在以init
做前缀的初始化快内,如下
class Student(name:String){
init{
logger.info("Student initialized with value ${name}")
}
}
kotlin中声明属性,还可以在构造函数中初始化属性
class Student(val name:String,val age :Int){}
和普通的构造函数一样,在主构造函数中的属性也可以使可变的var或者只读的val
如果构造函数有注解或者可见性声明,则constructor关键字是不可少的,并且可见性应该在前:
class Student public @inject constructor(name:String){}
二级构造函数
类也可以有二级构造函数,需要加前缀constructor
class Student{
constructor(parent:Student){
parent.children.add(this)
}
}
如果类有主构造函数,每个二级构造函数都要,或直接或间接通过另一个二级构造函数代理主构造函数,在同一个类中代理另一个构造函数使用this
关键字:
class Person(val name: String) {
constructor (name: String, paret: Person) : this(name) {
parent.children.add(this)
}
}
和java一样,如果一个非抽象类没有声明构造函数,则会默认有一个无参构造,该构造函数的可见性是public,如果不想你的类有公共的构造函数,可以声明一个拥有非默认可见性的空参构造
class DontCreatMe private constructor(){}
创建类的实例
val student=Student()
val student2=Student("ton")
kotlin中没有new关键字
类成员
类可以包含:
--构造函数和初始化代码块
--函数
--属性
--内部类
--对象声明
继承
kotlin中所有的类都有共同的父类Any
,它是一个木有父类声明的类的默认父类
class Example //默认继承Any
Any不是java.lang.Object;它的成员只有equal().hashCode()及toString()
声明一个明确的父类,需要在类头后面加冒号再加父类
且,在kotlin中,子类想要继承父类,需得父类开放,所以,如果想要子类继承,父类需要用open关键字修饰
open与java中的final作用正好相反,默认情况下,kotlin中所有类都是被final所修饰
,所以想要被继承,需要添加open
open class Base(p:Int)
class Child(p:Int):Base(p)
如果类有主构造函数,则父类可以而且是必须在主构造函数中使用参数立即初始化。
如果类没有主构造函数,则必须在每一个构造函数中用 super 关键字初始化父类,或者在代理另一个构造函数做这件事。注意在这种情形中不同的二级构造函数可以调用父类不同的构造方法:
class MyView : View {
constructor(ctx: Context) : super(ctx) {
}
constructor(ctx: Context, attrs: AttributeSet) : super(ctx,attrs) {
}
}
复写方法
不像 java ,kotlin 需要把可以复写的成员都明确注解出来
,并且重写它们,如下复写v方法
open class Base {
open fun v() {}
fun nv() {}
}
class Derived() : Base() {
override fun v() {}
}
对于 Derived.v() 来说override注解是必须的。如果没有加的话,编译器会提示。如果没有open注解,像 Base.nv() ,在子类中声明一个同样的函数是不合法的,要么加override要么不要复写。
在 final类(就是没有open注解的类)中,open 类型的成员是不允许的,即,只有被open修饰的类,其中的方法才能被复写
还要就是,标记为override
的成员时open的,它可以在子类中被复写,如果不想被复写就要加final
复写属性
复写属性与复写方法类似,在一个父类上声明的属性在子类上被重新声明,必须添加override,并且它们必须具有兼容的类型,每个被声明的属性都可以被一个带有初始化器的属性或带有getter方法的属性覆盖
open class Fu{
open val x:Int get{}
}
class Zi:Fu(){
override val x:Int=...
}
kotlin中val属性是可以被var属性覆盖的,但反之则不允许,因为val属性本质上声明了一个getter方法,并将其重写为var,另外在派生类中声明了setter方法
可以在主构造中使用override关键字作为属性声明的一部分
interface Fu{
val count:Int
}
class Zi(override val count:Int):Fu
class Zi2:Fu{
override var count:Int=0
}
复写规则
在kotlin中,实现继承通常遵循如下规则:如果一个类从它的直接父类继承了同一个成员的多个实现,即,他有多个父类,且每个父类中都有该成员的实现,那么它必须复写这个成员并且提供自己的实现(或者直接调用继承来的实现),
虽然有点绕,但通过下面例子,想必大家会理解的
open class A {
open fun f () { print("A") }
fun a() { print("a") }
}
interface B {
fun f() { print("B") } // 接口的成员变量默认是 open 的
fun b() { print("b") }
}
class C() : A() , B {
// 编译器会要求复写f()
override fun f() {
super<A>.f() // 调用 A.f()
super<B>.f() // 调用 B.f()
}
}
C可以同时从A和B中继承方法,而且C继承a()或者b()方法的实现,没有任何问题,因为它们都只有一个实现,但f()方法却又两个实现,所以必须重写f()方法并且提供自己的实现来消除歧义
抽象类
被abstract修饰的类被称为抽象类,抽象类中只是定义了方法,但没有做具体实现,需要子类去自行实现,且抽象类默认是被open修饰的.
可以用一个抽象的成员去复写一个带有open注解的非抽象方法
open class Base {
open fun f() {}
}
abstract class Derived : Base() {
override abstract fun f()
}
密封类
密封类用于代表严格的类结构,值只能是有限集合中的某中类型,不可以是任何其它类型。这就相当于一个枚举类的扩展:枚举值集合的类型是严格限制的,但每个枚举常量只有一个实例,而密封类的子类可以有包含不同状态的多个实例。
声明密封类需要在 class 前加一个 sealed
修饰符。密封类可以有子类但必须全部嵌套在密封类声明内部
sealed class Expr {
class Const(val number: Double) : Expr()
class Sum(val e1: Expr, val e2: Expr) : Expr()
object NotANumber : Expr()
}
密封类子类的扩展可以在任何地方,不必在密封类声明内部进行。
使用密封类的最主要的的好处体现在你使用 when 表达式。可以确保声明可以覆盖到所有的情形,不需要再使用 else 情形,如下
fun eval(expr: Expr): Double = when(expr) {
is Const -> expr.number
is Sum -> eval(expr.e1) + eval(expr.e2)
NotANumber -> Double.NaN
// the `else` clause is not required because we've covered all the cases
}
委托和代理
委托是把事情托付给别人或别的机构办理
代理是指以他人的名义,在授权范围内进行对被代理人直接发生法律效力的法律行为,代理的产生,可以是受他人委托
我们以大头儿子和小头爸爸的故事来讲一下kotlin中的委托和代理
//洗碗的接口
interface IWashBowl{
fun wash()
}
因为大头儿子和小头爸爸都有洗碗的能力,所以小头爸爸就可以通过by委托大头儿子去洗碗
//大头儿子
class BigHeadSon:IWashBowl{
override fun wash() {
println("1")
}
小头爸爸通过by让大头儿子洗碗
//小头爸爸
class smallHeadFathoe :IWashBowl by BigHeadSon(){
override fun wash() {
BigHeadSon().wash()
}
单例模式
kotlin中的单例模式,把class的声明变成object来定义单例
object WEIqunMother:IWashBowl{
override fun wash() {}
}
jilab.jpg
网友评论