面向对象
package learn
class father(val str:String){
val string=str;
fun start(){
println("${string}:kotlin")
}
}
使用上面的father类
import learn.father
fun main(args: Array<String>) {
val father=father("hello")
father.start()
}
结果
继承
/**
* 定义一个父类
*/
open class father(open val str:String) {
open fun start() {
println("father")
}
}
/**
* 定义一个子类
*/
class son(override val str :String):father(str){
override fun start()
{
println("son")
}
}
main函数代码
fun main(args: Array<String>) {
val father1: father = son("hello")
val son = son("hello")
val father2 = father("hello")
father1.start()
son.start()
father2.start()
}
总结:kotlin的写法跟java写法有很大的不同,kotlin的继承用的是冒号,被继承的father类要在class加上open关键词才可以被继承,子类继承父类是要实现父类的构造函数。子类重写父类方法是父类方法前要加open关键词,子类方法前面要加override关键词,使用var father:father=son("son")是还是跟java一样,左边是编译,右边是运行,也就是调用start方法还是输出son;
复写规则
在 kotlin 中,实现继承通常遵循如下规则:如果一个类从它的直接父类继承了同一个成员的多个实现,那么它必须复写这个成员并且提供自己的实现(或许只是直接用了继承来的实现)。为表示使用父类中提供的方法我们用 super<Base>
表示:
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()
}
}
可以同时从 A 和 B 中继承方法,而且 C 继承 a() 或 b() 的实现没有任何问题,因为它们都只有一个实现。但是 f() 有俩个实现,因此我们在 C 中必须复写 f() 并且提供自己的实现来消除歧义。
抽象类
一个类或一些成员可能被声明成 abstract 。一个抽象方法在它的类中没有实现方法。记住我们不用给一个抽象类或函数添加 open 注解,它默认是带着的。
我们可以用一个抽象成员去复写一个带 open 注解的非抽象方法。
open class Base {
open fun f() {}
}
abstract class Derived : Base() {
override abstract fun f()
}
伴随对象
在 kotlin 中不像 java 或者 C# 它没有静态方法。在大多数情形下,我们建议只用包级别的函数。
如果你要写一个没有实例类就可以调用的方法,但需要访问到类内部(比如说一个工厂方法),你可以把它写成它所在类的一个成员(you can write it as a member of an object declaration inside that class)
更高效的方法是,你可以在你的类中声明一个伴随对象,这样你就可以像 java/c# 那样把它当做静态方法调用,只需要它的类名做一个识别就好了
密封类
密封类用于代表严格的类结构,值只能是有限集合中的某中类型,不可以是任何其它类型。这就相当于一个枚举类的扩展:枚举值集合的类型是严格限制的,但每个枚举常量只有一个实例,而密封类的子类可以有包含不同状态的多个实例。
声明密封类需要在 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
}