Kotlin类和对象

类和对象
创建类:
class Person constructor(name: String) {
    var name: String
    	get() = field.toUpperCase()
    	set(value) {
            if (value == null) {       
                field = ""
            } else {
                field = value        
            }
        }
}

使用:

	val person = Person("name")
    person.name = "hello"				//这里实际上调用的是person.setName(hello)
    print(person.name)					//这里实际上调用的是person.getName()方法,所以打印结果是HELLO

这里变量的set get方法中用有两个参数,filed表示当前的成员变量,value表示set方法传如的参数,这样设计的原因是,如果set方法中使用的是name = xxx,那么这句赋值又会调用自身的set方法,从而导致递归的死循环;

另外根据定义,val类型的变量不能有set方法

次构造器:
class Person(name: String) {
	//所有的次构造器都要代理主构造器
    constructor(name: String, test: Test) : this(name) {
        this.test= test;
    }

    var name = name
        
    //可以使用lateinit在次构造器或init中延迟加载,但它只能修饰非基本类型
    lateinit var test :Test
    
	//如果是基本类型,而主构造器中又没有该字段,只能声明为Int?并临时赋值
	var age :Int? = null
}
嵌套类:

嵌套类类似与java的静态内部类,构造嵌套类不需要外部类的实例;

class Outer {                  // 外部类
    private val bar: Int = 1
    class Nested {             // 嵌套类
        fun foo() = 2
    }
}

fun main(args: Array<String>) {
    val demo = Outer.Nested().foo() // 调用格式:外部类.嵌套类.嵌套类方法/属性
    println(demo)    // == 2
}
内部类:

内部类同java的内部类,要想构造内部类必须构造外部类的实例,

class Outer {
    private val bar: Int = 1
    var v = "成员属性"
    
    inner class Inner {
        fun foo() = bar  // 访问外部类成员
        fun innerTest() {
            var o = this@Outer //获取外部类的成员变量
            println("内部类可以引用外部类的成员,例如:" + o.v)
        }
    }
}

fun main() {
    val demo = Outer().Inner().foo()
    println(demo) //   1
    val demo2 = Outer().Inner().innerTest()   
    println(demo2)   // 内部类可以引用外部类的成员,例如:成员属性
}
匿名内部类:
test.setInterFace(object : TestInterFace {
     override fun test() {
            println("对象表达式创建匿名内部类的实例")
     }
})
类修饰符:
//类属性修饰符
abstract    // 抽象类  
open        // 类可继承,类默认是final的
final       // 类不可继承,默认属性
enum        // 枚举类
annotation  // 注解类

访问权限修饰符
private    
protected  
public    
internal   // 同一个模块中可见

继承和接口

所有类都隐式继承Any,Any提供了三个函数:

equals()
hashCode()
toString()
继承:

要想被继承必须要被open修饰,子类必须要继承父类的某个构造器,即必须直接或间接继承主构造器:
同样的,想要被重写的函数也必须要用open修饰

open class Person(name: String) {
    var name = name

    open var age: Int? = null

    constructor(name: String, age: Int) : this(name) {
        this.age = age
    }

	open fun sleep() {
        print("睡觉")
    }
}

class Student(name: String, age: Int) : Person(name) {
	//重写age变量,重写变量的数据类型不能改变,但是可以用var重写val变量
	override var age = age
    var id: String? = null
    
    //重写方法
    override fun sleep() {
        print("上课睡觉")
    }
}

同Java类似,Kotlin不支持多继承

接口:

继承类和实现接口的区别是,继承类要继承其构造方法(就是后边带括号),实现接口后边没有括号和参数

interface MyInterface {
	var name:String 			//name 属性是抽象的
    fun fun1()    				//未实现
    fun fun2() {  				//可以实现默认方法
      println("fun2")
    }
}

//实现接口
class Person: MyInterface {
	override var name: String = "Person" //重写属性
    override fun fun1() {
        // 方法体
    }
}

由于接口可以有默认实现,所以需要在继承多个接口时区分不同接口的同名函数:

interface A {
    fun fun1() { print("fun1") }   
    fun fun2()                  
}
 
interface B {
    fun fun1() { print("B") }   
    fun fun2()
}

class C : A, B {
    override fun foo() {
        super<A>.fun1()
        super<B>.fun1()
    }
 
    override fun fun2() {
        super<B>.fun2()
    }
}
函数扩展:
class Person(var name:String)

//成员函数和扩展函数同名时优先使用成员函数
//扩展函数不需要写在类中,直接在kotlin文件中定义一个方法就好了
fun Person.Print(){				
    print("用户名 $name")
}

fun main() {
    var person = Person("Tom")
    person.Print()
}
伴生对象:
class Student(name: String, age: Int?) : Person(name) {
    companion object {							//object后面可以加类名,一般省略
        var name = "Tom"
        fun getName(): String{
            return name
        }
    }
}

 fun main() {
      print(Studnet.name);
      print(Studnet.getName);
}

一个类中只能声明一个companion对象,companion对象类似于Java中的static对象

数据类

用data关键字声明数据类:

data class Person(val name: String, val age: Int)

数据
1.主构造函数至少包含一个参数。
2.所有的主构造函数的参数必须标识为val 或者 var ;
3.数据类不可以声明为 abstract, open, sealed 或者 inner;
4.数据类不能继承其他类 ,但是可以实现接口

对象属性修改:

data class Person(val name: String, val age: Int)

fun main() {
        val p1 = Person("Tom", 12)
        val p2 = p1.copy(name = "Bob")
        print(p1.toString())			//Person(name=Tom, age=12)
        print(p2.toString())			//Person(name=Bob, age=12)
        person.name = "ppp"				//val类型的属性不能修改它的内容,除非生命为var
    }
密封类
泛型
class Box<T>(t: T) {
    var value = t
}

fun(){
	val box1 = boxIn<Int>(1)
	val box2 = boxIn(1)				//自动推断类型
}

泛型函数:

fun <T> print(content: T) {
    when (content) {
        is Int -> println("Int")
        is String -> println("String ")
        else -> println("other")
    }
}

泛型约束:

fun <T : Person> get() {
	//限制T必须是Person的子类
}

协变(out)和逆变(in)
将泛型作为内部方法的返回,用 out:

interface Production<out T> {
    fun produce(): T							//T只能用作函数的返回,而不能用T作为函数参数
}

将泛型对象作为函数的参数,用 in:

interface Consumer<in T> {
    fun consume(item: T)						//T只能用作函数的参数,而不能返回T类型的对象
}

既将泛型作为函数参数,又将泛型作为函数的输出,那就既不用 in 或 out。

interface ProductionConsumer<T> {
    fun produce(): T
    fun consume(item: T)
}
枚举类:

简单枚举:

enum class Color {
    RED, GREEN, BLUE
}

带参数:

enum class Color(val rgb: Int) {
    RED(0xFF0000),
    GREEN(0x00FF00),
    BLUE(0x0000FF)
}

fun main(){
	Color.RED.rgb		
}

带匿名方法:

enum class Color {
    RED {
        override fun draw() {
            print("red")
        }
    },
    WHITE {
        override fun draw() {
            print("white")
        }
    };
    
    abstract fun draw()
}

fun main(){
	Color.RED.draw()
	Color.WHITE .draw()
}
object:
fun main(args: Array<String>) {
    val temp = object {
        var name = "hello world"
    }
    println(site.name)
}

object还可以用来实现匿名内部类:

open class Student(var v: String?) {
    var name: String? = null
}

var school = School(object : Student("Tom") {
     var age = 12
})

object还可以用来实现单例:

object DataManager {
    var data: IntArray? = null
}

//访问data直接用类名+变量名
DataManager.data
代理:
interface Base {
    fun print()
}

class BaseImpl : Base {
    override fun print() {
        print("hello world")
    }
}
//代理类声明
class BaseProxy(base: Base) : Base by base

fun main() {
	BaseProxy(BaseImpl()).print()
}

属性代理:

class Person {
    var id: String by PersonDelegate()
}

class PersonDelegate {
    operator fun getValue(ref: Any?, property: KProperty<*>): String {
        return (ref as Person).id				//这样写会由于递归导致栈溢出
    }

    operator fun setValue(ref: Any?, property: KProperty<*>, value: String) {
        //这里已经自动给ref赋值了,只要添加其他逻辑就好了
        return
    }
}

几种标准代理:

1.延迟初始化代理:

val id: String by lazy {
     print("call set id")
     "Hello"
}

lazy中的代码块只会在初始化时执行一次

2.观察者代理:

var id: String by Delegates.observable("init") { property, oldValue, newValue ->
    print(property.name + " oldValue=" + oldValue + " newValue=" + newValue)
}

3.属性映射代理:
可以用一个map来初始化类:

class Person(map: Map<String, Any?>) {
    val name: String by map
    val age: Int by map
}

fun main(){
	var p = Person(mapOf("name" to "Tom", "age" to 12))
    print(p.name + p.age)
}

如果Person的成员变量类型是var,需要用MutableMap来初始化

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值