Kotlin类和对象_接口_抽象类

Kotlin支持面向对象编程(OOP)以及函数式编程。 面向对象编程基于对象和类。
Kotlin还支持OOP语言的支柱,如:封装,继承和多态。
Kotlin类与Java类基本类似,类是具有共同属性的对象的蓝图。 Kotlin类使用关键字class声明。 Kotlin类有一个类头,它指定了它的类型参数,构造函数等,以及由花括号包围的类体。

class Account {
    var acc_no: Int = 0
    var name: String? = null
    var amount: Float = 0f
    fun insert(ac: Int,n: String, am: Float ) {
        acc_no=ac
        name=n
        amount=am
        println("账号: ${acc_no} ,账户名 :${name},总金额 :${amount}")
    }
    fun deposit() {
        //deposite code
    }
    fun withdraw() {
        // withdraw code
    }
    fun checkBalance() {
        //balance check code
    }
}
Account类有三个属性acc_no,name,amount和三个成员函数:deposit(),withdraw(),checkBalance()。
在Kotlin中,属性必须初始化或声明为抽象。 在上面的类中,属性acc_no初始化为0,name为null,amount为0f。
在引用的时候:
fun main(args: Array<String>){
   // Account()
    var acc= Account()
    acc.insert(832345,"Maxsu",1000f) // 访问成员函数
    println("${acc.name}") // 访问类属性
}

嵌套类和内部类
嵌套类
嵌套类是在另一个类中创建的类。 在Kotlin中,嵌套类默认是静态的,因此可以在不创建类对象的情况下访问其数据成员和成员函数。 嵌套类无法访问外部类的数据成员。

示例代码:
class outerClass{
    private var name: String = "Ashu"
    class nestedClass{
        var description: String = "code inside nested class"
        private var id: Int = 101
        fun foo(){
            //  print("name is ${name}") // cannot access the outer class member
            println("Id is ${id}")
        }
    }
}
fun main(args: Array<String>){
	// nested class must be initialize
    println(outerClass.nestedClass().description) // accessing property
    var obj = outerClass.nestedClass() // object creation
    obj.foo() // access member function
}

Kotlin内部类
内部类是一个使用关键字inner在一个类中创建的类。 换句话说,可以说标记为inner的嵌套类称为内部类。
内部类不能在接口或非内部嵌套类中声明。内部类优于嵌套类的优点是,
即使它是私有的,它也能够访问外部类的成员。 内部类保持对外部类的对象的引用。

class Outer {
    private val bar: Int = 1
    var v = "成员属性"
    /**嵌套内部类**/
    inner class Inner {
        fun foo() = bar  // 访问外部类成员
        fun innerTest() {
           //为了消除歧义,要访问来自外部作用域的 this,我们使用this@label,其中 @label 是一个 代指 this 来源的标签。
            var o = this@Outer //获取外部类的成员变量
            println("内部类可以引用外部类的成员,例如:" + o.v)
        }
    }
}

fun main(args: Array<String>) {
    val demo = Outer().Inner().foo()
    println(demo) //   1
    val demo2 = Outer().Inner().innerTest()   
    println(demo2)   // 内部类可以引用外部类的成员,例如:成员属性
}
**区别**
嵌套类和内部类在使用时的区别
var demo = Outter.Nested()// 嵌套类,Outter后边没有括号
var demo = Outter().Inner();// 内部类,Outter后边有括号
要想构造内部类的对象,必须先构造外部类的对象,而嵌套类则不需要;

Kotlin构造函数
在Kotlin中,构造函数是一个类似于方法的代码块。 声明构造函数的名称与类的名称相同,后跟括号()。 构造函数用于在创建对象时初始化变量。
Kotlin构造函数的类型Kotlin中有两种类型的构造函数:
1.0主构造函数
2.0辅助构造函数
Kotlin类中只有一个主要构造函数,而辅助构造函数可以是一个或多个。
主构造函数
主构造函数用于初始化类,它在类标题中声明。 主构造函数代码由带有可选参数的括号括起

//声明参数name是只读属性,而id是读取和写入属性
class myClass constructor(val name: String, var id: Int) {
}
**如果主构造器没有任何注解,也没有任何可见度修饰符,那么constructor关键字可以省略。**
class myClass (val name: String, var id: Int) {
}
fun main(args: Array<String>){
    val myclass = myClass ("Susen", 10010)
    println("Name = ${ myclass.name}")
    println("Id = ${ myclass.id}")
}

初始化块的主构造函数
主构造函数不包含任何代码,初始化程序块用于初始化代码。 该块是以init关键字为前缀。 在实例初始化期间,初始化块的执行顺序与它们在类体中出现的顺序相同。

class myClass(name: String, id: Int) {
    val e_name: String
    var e_id: Int
    init{
        e_name = name.capitalize()
        e_id = id

        println("Name = ${e_name}")
        println("Id = ${e_id}")
    }
}
fun main(args: Array<String>){
    val myclass = myClass ("Maxsu", 10010)

}
//声明name和id属性时没有val或var,因此它们不是myClass类的属性,只是作为参数传入
e_name和e_id才是类的属性

Kotlin辅助构造函数
Kotlin在类中创建一个或多个辅助构造函数。 使用constructor关键字创建辅助构造函数。

class MyClass{
    var c_id:Int = 0
    var c_name:String? = null
    constructor(id: Int){
        c_id = id
    }
    constructor(name: String, id: Int){
        c_id = id
        c_name =name
    }
}
在引用的时候:
var my = MyClass(1)
var my2 = MyClass("",1)

也可以在同一个类中使用主和辅助构造函数。 通过在同一个类中使用主和辅助构造函数,辅助构造函数需要授权给主构造函数。 使用this()关键字对同一个类中的另一个构造函数进行授权。
如果类有主构造函数,每个次构造函数都要,或直接或间接通过另一个次构造函数代理主构造函数。在同一个类中代理另一个构造函数使用 this 关键字:

class myClass(password: String){
    constructor(name: String, id: Int, password: String): this(password){
        println("Name = ${name}")
        println("Id = ${id}")
        println("Password = ${password}")
    }
}
fun main(args: Array<String>){
    val myclass = myClass ("Maxsu", 101, "passwd123")

}

从同一个类的一个辅助构造函数调用另一个辅助构造函数
在Kotlin中,一个辅助构造函数可以调用同一个类的另一个辅助构造函数。 可通过使用this()关键字完成的。

class myClass{

    constructor(name: String, id: Int): this(name,id, "mypassword"){
        println("第二个执行")
        println("Name = ${name}")
        println("Id = ${id}")
    }

    constructor(name: String, id: Int,pass: String){
        println("第一个执行")
        println("Name = ${name}")
        println("Id = ${id}")
        println("Password = ${pass}")
    }
}
fun main(args: Array<String>){
    val myclass = myClass ("Maxsu", 10010)
}

从派生类辅助构造函数调用超类辅助构造函数在Kotlin中,一个派生类的辅助构造函数可以调用基类的辅助构造函数。可使用super关键字完成的,它是继承的概念。

open class Parent{

    constructor(name: String, id: Int){
        println("第一个执行")
        println("Name = ${name}")
        println("Id = ${id}")
    }

    constructor(name: String, id: Int,pass: String){
        println("第三个执行")
        println("Name = ${name}")
        println("Id = ${id}")
        println("Password = ${pass}")
    }
}
class Child: Parent{
    constructor(name: String, id: Int): super(name,id){
        println("第二个执行")
        println("Name = ${name}")
        println("Id = ${id}")
    }

    constructor(name: String, id: Int,pass: String):super(name,id,"password"){
        println("第四个执行")
        println("Name = ${name}")
        println("Id = ${id}")
        println("Password = ${pass}")
    }
}
fun main(args: Array<String>){
    val obj1 = Child("Susen", 10010)
    val obj2 = Child("Susen", 10010,"mypassword")
}

accessModifier: 访问权限修饰符:
1.public:公开可见
2.protected:仅允许对其类或子类进行可见性
3.internal:使字段仅在实现它的模块内可见。
4.private:允许声明仅在声明属性,字段等的块内可访问,不允许访问范围外部。可以在该特定文件中访问私有包
classModifier: 类属性修饰符,标示类本身特性。
1.abstract // 抽象类
2.final // 类不可继承,默认属性
3.enum // 枚举类
4.open // 类可继承,类默认是final的
5.annotation // 注解类
类的继承
当两个或多个类具有相同的属性时,这就引入继承的概念。 继承用于提高代码可重用性。
派生类只有一个基类,但可以有多个接口,而基类可能有一个或多个派生类
(1)由于Kotlin类默认为final,因此不能简单地继承它们。在类之前使用open关键字来为其它类继承这个类。
(2)当继承一个类来派生类时,所有的字段和函数都是继承的。 可以在派生类中使用这些字段和函数。

open class Employee(name: String, age: Int, salary: Float) {  
    // code of employee  
}  

class Programmer(name: String, age: Int, salary: Float): Employee(name,age,salary) {  
    // code of programmer  
}  

class Salesman(name: String, age: Int, salary: Float): Employee(name,age,salary) {  
    // code of salesman  
}

Kotlin继承和主要构造函数
如果基类和派生类都具有主构造函数,则参数在基类的主构造函数中初始化。
在上面的继承示例中,所有类都包含三个参数:name,age和salary,
所有这些参数都在基类的主构造函数中初始化。
当基类和派生类在主构造函数中包含不同数量的参数时,基类参数将从派生类对象初始化。

open class Employee(name: String,salary: Float) {
    init {
        println("姓名:$name.")
        println("薪水:$salary")
    }
}
class Programmer(name: String, dept: String, salary: Float):Employee(name,salary){
    init {
        println("$name 所在部门:$dept ,薪水为:$salary.")
    }
    fun doProgram() {
        println("编程我有激情.")

    }
}
class Salesman(name: String, dept: String, salary: Float):Employee(name,salary){
    init {
        println("$name 所在部门:$dept ,薪水为:$salary.")
    }
    fun fieldWork() {
        println("我的爱好是:旅游.")

    }
}
fun main(args: Array<String>){
    val obj1 = Programmer("Susen", "技术部", 40000f)
    obj1.doProgram()
    println()
    val obj2 = Salesman("Ajax", "市场部", 30000f)
    obj2.fieldWork()
}

Kotlin继承和辅助构造函数
如果派生类不包含任何主构造函数,则需要使用super关键字从派生类调用基类辅助构造函数。

	open class Patent {
	    constructor(name: String, id: Int) {
	        println("执行超类构造函数: $id , $name ")
	    }
	}
	
	class Child: Patent {
	
	    constructor(name: String, id: Int, dept: String): super(name, id) {
	        print("使用属性执行子类构造函数:$name, $id, $dept")
	    }
	}
	fun main(args: Array<String>) {
	    val child = Child("Maxsu",10010, "技术部")
	}

Kotlin方法覆盖方法
覆盖意味着将super(parent)类的方法的特定实现提供到子类(子)类中。
换句话说,当子类重新定义或修改其超类的方法为子类时,它被称为方法覆盖。 方法覆盖只能在继承中实现。
Kotlin方法覆盖的规则:
1.0父类及要覆盖的方法或属性必须是open的(非final)。
2.0基类和派生类的方法名必须相同。
3.0方法必须具有与基类相同的参数。
4.0如果要覆盖父类的方法,必须将要覆盖的父类及方法声明为open。 同时,在子类中重写的方法必须以override关键字开头。

	open class Bird {
	    open fun fly() {
	        println("Bird is flying...")
	    }
	}
	class Parrot: Bird() {
	    override fun fly() {
	        println("Parrot is flying...")
	    }
	}
	class Duck: Bird() {
	    override fun fly() {
	        println("Duck is flying...")
	    }
	}
	fun main(args: Array<String>) {
	    val p = Parrot()
	    p.fly()
	    val d = Duck()
	    d.fly()
	}

5.0派生类也可以使用super关键字调用超类方法和属性。

open class Bird {
    open var color = "黑色"
    open fun fly() {
        println("Bird is flying...")
    }
}
class Parrot: Bird() {
    override var color = "绿色"
    override fun fly() {
        super.fly()
        println("Parrot is flying...")
    }
}

fun main(args: Array<String>) {
    val p = Parrot()
    p.fly()
    println(p.color)

}

Kotlin多类实现
在Kotlin中,派生类在尖括号中使用超类型名称,即,super ,当它实现多个类中提供的相同函数名时。
例如,派生类Parrot扩展超类Bird并实现相同的Duck接口函数fly()。 要调用每个类和接口的特定方法,必须在尖括号中提到超类型名称为super .fly()和super .fly()。(在实际开发中要尽量避免这个问题)

open class Bird {
    open var color = "黑色"
    open fun fly() {
        println("Bird is flying...")
    }
}
interface Duck {
    fun fly() {
        println("Duck is flying...")
    }
}
class Parrot: Bird(),Duck {
    override var color = "绿色"
    override fun fly() {
        super<Bird>.fly()
        super<Duck>.fly()
        println("Parrot is flying...")

    }
}
fun main(args: Array<String>) {
    val p = Parrot()
    p.fly()
    println(p.color)

}

Kotlin抽象类
1.0使用abstract关键字声明的类称为抽象类。 无法实例化抽象类。 意思是,不能创建抽象类的对象。
显式使用abstract关键声明类,才能表示抽象类的方法和属性,否则它是非抽象的。
2.0抽象类是部分定义的类,方法和属性,它们不是实现,但必须在派生类中实现。
如果派生类没有实现基类的属性或方法,那么它也是一个抽象类。
3.0抽象类或抽象函数不需要使用open关键字进行批注,因为它们默认是开放的。
抽象成员函数不包含实现主体。 如果成员函数在抽象类中包含有函数的实现,则不能将声明为abstract。

abstract class Car{
    abstract fun run()
}
class Honda: Car(){
    override fun run(){
        println("Honda is running safely..")
    }
}
fun main(args: Array<String>){
    val obj = Honda()
    obj.run();
}

4.0非抽象的open成员函数可以在抽象类中重载。

open class Car {
    open fun run() {
        println("Car is running..")
    }
}
abstract class Honda : Car() {
    override abstract fun run()
}
class City: Honda(){
    override fun run() {
        //  TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
        println("Honda City is running..")
    }
}
fun main(args: Array<String>){
    val car = Car()
    car.run()
    val city = City()
    city.run()
}

Kotlin接口
接口是类的蓝图(基础框架)。Kotlin接口类似于Java 8中的接口,它包含抽象方法声明以及方法的实现
接口是使用interface关键字来定义的
默认情况下,仅在没有方法体(方法只声明未实现)的情况下声明的方法是抽象的
父类或接口实现的扩展是在子类中使用(:)运算符完成的(这一点跟继承相同,不同点在于接口没有构造函数)

interface MyInterface {
    val id: Int // abstract property  
    fun absMethod()// abstract method  
    fun doSomthing() {
        // optional body  
    }
}

使用接口的优点
1.0使用接口支持多重继承功能。
2.0它可以用来实现松耦合。
3.0它用于实现抽象。
4.0一个类只能扩展一个超类但可以实现多个接口。

interface MyInterface1 {
    fun doSomthing()
}
interface MyInterface2 {
    fun absMethod()
}
class MyClass : MyInterface1, MyInterface2 {
    override fun doSomthing() {
        println("overriding doSomthing() of MyInterface1")
    }

    override fun absMethod() {
        println("overriding absMethod() of MyInterface2")
    }
}
fun main(args: Array<String>) {
    val myClass = MyClass()
    myClass.doSomthing()
    myClass.absMethod()
}

匿名内部类

class Test {
    var v = "成员属性"
    fun setInterFace(test: TestInterFace) {
        test.test()
    }
}
/**
 * 定义接口
 */
interface TestInterFace {
    fun test()
}

fun main(args: Array<String>) {
    var test = Test()
    /**
     * 采用对象表达式来创建接口对象,即匿名内部类的实例。
     */
    //特别注意这里的 object : TestInterFace,这个 object 是 Kotlin 的关键字,要实现匿名内部类,
    //就必须使用 object 关键字,不能随意替换其它单词,切记切记。
    test.setInterFace(object : TestInterFace {
        override fun test() {
            println("对象表达式创建匿名内部类的实例")
        }
    })
}

Kotlin Data类
声明数据类必须至少包含一个带有属性参数(val或var)的主构造函数。
数据类不能是抽象的,内部的,开放的或密封的。
使用data修饰类,重写了以下函数:
equals():Boolean
hashCode(): Int
toString(): String
component() 函数对应的属性
copy()

示例:
data class User(var name: String, var id: Int, var email: String)

fun main(agrs: Array<String>) {
    val u = User("Maxsu", 10010, "maxsu@yiibai.com")
    println(u)
}

Kotlin Sealed类
关于封闭类看这个
密封(Sealed)类是一个限制类层次结构的类。 可以在类名之前使用sealed关键字将类声明为密封类。 它用于表示受限制的类层次结构。
当对象具有来自有限集的类型之一,但不能具有任何其他类型时,使用密封类。密封类的构造函数在默认情况下是私有的,它也不能允许声明为非私有。
密封类和 when 的使用密封类通常与表达时一起使用。 由于密封类的子类将自身类型作为一种情况。 因此,密封类中的when表达式涵盖所有情况,从而避免使用else子句。(类似于枚举)

sealed class Shape{
    class Circle(var radius: Float): Shape()
    class Square(var length: Int): Shape()
    class Rectangle(var length: Int, var breadth: Int): Shape()
    //  object NotAShape : Shape()  
}

fun eval(e: Shape) =
    when (e) {
        is Shape.Circle ->println("Circle area is ${3.14*e.radius*e.radius}")
        is Shape.Square ->println("Square area is ${e.length*e.length}")
        is Shape.Rectangle ->println("Rectagle area is ${e.length*e.breadth}")
        //else -> "else case is not require as all case is covered above"  
        //  Shape.NotAShape ->Double.NaN  
    }
fun main(args: Array<String>) {

    var circle = Shape.Circle(5.0f)
    var square = Shape.Square(5)
    var rectangle = Shape.Rectangle(4,5)

    eval(circle)
    eval(square)
    eval(rectangle)
}  

从Kotlin调用Java代码
如果想要从Kotlin文件调用存在于不同包中的Java代码,则需要在Kotlin文件中使用Java类导入包名

//无返回值
fun main(args: Array<String>) {
    val sum= MyJavaClass.add(5, 10)
    println("printing sum inside Kotlin file: "+sum)
}
public class MyJavaClass {
    public static void main(String[] args){

    }
    public static void add(int a,int b){
        int result = a + b;
        System.out.println("printing inside Java class :"+result);
    }
}
//有返回值
fun main(args: Array<String>) {
    val area: Int = MyJavaClass.area(3, 4)
    println("printing area from java insideKotlin file: "+area)
}
public class MyJavaClass {
    public static void main(String[] args){

    }
    public static int area(int a, int b){
        int result = a * b;
        return result;
    }
}

从Java调用Kotlin代码

	//kotlin代码
	fun main(args: Array<String>){  
			//code  
	}  
	fun area(a: Int, b: Int):Int{
	    return a*b
	}
	//java代码
	public class MyJava {
		    public static void main(String[] args) {
		        int area = MyKotlinKt.area(4,5);
		        System.out.print("printing area inside Java class returning from Kotlin file: "+area);
		    }
	}
	如果想要从Java类调用不同包中的Kotlin代码,则需要在Java类中导入包含Kotlin文件名的包名,
	并从Java类调用Kotlin代码。 另一种方法是指定完整路径:packageName.KotlinFileKt.methodName()来调用

使用注解**@JvmName**更改Kotlin文件名
编写Kotlin代码并在顶部放置注解@file:JvmName(“MyKotlinFileName”)。 编译Kotlin代码后,文件名将更改为注释中提供的名称(如:MyKotlinFileName)。 在访问MyKotlin.kt的代码时,需要使用文件名:MyKotlinFileName。

//kotlin代码
@file: JvmName("MyKotlinFileName")
package mykotlinpackage
fun main(args: Array<String>) {
}
fun area(l: Int,b: Int):Int{
    return l*b
}
//java引用
package myjavapackage;
import mykotlinpackage.MyKotlinFileName;
public class MyJavaClass {
    public static void main(String[] args){
        int area = MyKotlinFileName.area(4,5);
        System.out.println("printing area inside Java class returning from Kotlin file: "+area);
    }
}

使用**@JvmMultifileClass**调用具有相同Java类名的多个文件方法
如果Kotlin的多个文件使用@JvmName注解生成相同的Java文件名,则通常在从Java文件调用时会出错。 但是,Kotlin编译器生成单个Java façade类,其中包含生成的Java文件以及具有相同名称的文件的所有声明。 为了激活façade类,我们在所有文件中使用@JvmMultifileClass注解。

文件:MyKotlin1.kt
@file: JvmName("MyKotlinFileName")
@file:JvmMultifileClass
package mykotlinpackage
fun main(args: Array<String>) {
}
fun area(l: Int,b: Int):Int{
    return l*b
}

文件:MyKotlin2.kt
@file: JvmName("MyKotlinFileName")
@file:JvmMultifileClass
package mykotlinpackage
fun volume(l: Int,b: Int,h: Int):Int{
    return l*b*h
}
文件:MyJava.java
package myjavapackage;
import mykotlinpackage.MyKotlinFileName;
public class MyJavaClass {
    public static void main(String[] args){
        int area = MyKotlinFileName.area(4,5);
        System.out.println("printing area inside Java class returning from Kotlin file: "+area);
        int vol = MyKotlinFileName.volume(4,5,6);
        System.out.println("printing volume inside Java class returning from Kotlin file: "+vol);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值