Android Kotlin开发语言学习笔记

Android Kotlin开发语言学习笔记

基本数值类型 Byte、Short、Int、Long、Float、Double 等。不同于 Java 的是,字符不属于数值类型,是一个独立的数据类型:

//基本数值类型包括 Byte、Short、Int、Long、Float、Double 等。不同于 Java 的是,字符不属于数值类型,是一个独立的数据类型
    var byteValue: Byte = 123
    var shortValue: Short = 123
    var intValue: Int = 123
    var longValue: Long = 123L
    var floatValue: Float = 23.23f
    var doubleValue: Double = 23.23

变量定义:

var name:String = "张三"			//var 可变变量
val age:Int =18						//val 不可变变量,此时对age进行++或--都会报Val cannot be reassigned的错误

初始化变量为null的操作(添加?):

var name:String=null;		//这样写会报Null can not be a value of a non-null type String的错误
var name:String? = null;	//如果一定要写null,可这样写,添加一个?,意味着后续可以给变量赋值为null
//类型后面加?表示可为空
var age: String? = "23" 
//抛出空指针异常
val ages = age!!.toInt()
//不做处理返回 null
val ages1 = age?.toInt()
//age为空返回-1
val ages2 = age?.toInt() ?: -1
//当一个引用可能为 null 值时, 对应的类型声明必须明确地标记为可为 null。
//当 str 中的字符串内容不是一个整数时, 返回 null:
fun parseInt(str: String): Int? {
  // ...
}

条件判断:

val count: Int =18
var msg:String
//条件判断格式1:(if else模式)
if(count<18){
     msg="你还是个少年"
}else if (count>=18&&count<30){
     msg="你已经成年啦"
}else{
     msg="你已经过了而立之年啦"
}
//条件判断格式2:(when模式)
var msg1:String = when {
    count<18 -> "未成年"
    count>=18&&count<30 -> "成年啦"
    else -> "而立"
}

函数定义格式:

//函数的定义
fun getString(count:Int):String{
    var msg1:String = when {
        count<18 -> "未成年"
        count>=18&&count<30 -> "成年啦"
        else -> "而立"
    }
    return msg1
}
//调用函数
val msg = getString(count)

可变长参数vararg的使用:

/**
 * vararg 可变长参数字段,用于可变长参数传递
 */
fun vars(vararg v: Int) {
    for (vt in v) {
        print(vt)
    }
}
//调用
vars(1, 2, 3, 4, 5, 6, 7, 8, 9)

字符串模板使用:

/**
 * 字符串模板
 * $ 表示一个变量名或者变量值
 * $varName 表示变量值
 * ${varName.fun()} 表示变量的方法返回值
 */
fun strFom(str1:String,str2:String): String{
        println("str1 is $str1 ,str2 is $str2")
        return str1+str2
}

//调用
println("返回值是: ${strFom("hello ","world")}")

数值类型判断字符is,相当于java中的instanceof:

/**
 * 类型判断字符is,相当于java中的instanceof
 */
fun objectType(obj : Any):String?{
        when{
                obj is String -> return "String"
                obj is Int ->return "Int"
                else -> return "other"
        }
        return null
}

//调用:
println("值类型是: ${objectType("hello")}")

for循环中的区间使用:区间 in 与 downTo ,步长step:

/**
 * 区间 in 与 downTo ,步长step,
 * 区间表达式由具有操作符形式 .. 的 rangeTo 函数辅以 in 和 !in 形成。
 * 区间是为任何可比较类型定义的,但对于整型原生类型,它有一个优化的实现。
 */
fun testfun() {
    //等同于 1 <= i && i <= 10,输出1到10
    for (i in 1..10) {
        println(i)
    }
    // 使用 step 指定步长
    for (i in 1..4 step 2) {
        println(i) // 输出“13”
    }
    //downTo,值从大到小
    for (i in 4 downTo 1 step 2) {
        println(i) // 输出“42”
    }
    // 使用 until 函数排除结束元素
    for (i in 1 until 10) {
        println(i)  // i in [1, 10) 排除了 10
    }
}

比较两个数字
Kotlin 中没有基础数据类型,只有封装的数字类型,你每定义的一个变量,其实 Kotlin 帮你封装了一个对象,这样可以保证不会出现空指针。数字类型也一样,所以在比较两个数字的时候,就有比较数据大小和比较两个对象是否相同的区别了。

在 Kotlin 中,三个等号 === 表示比较对象地址,两个 == 表示比较两个值大小。

val a: Int = 10000
    println(a === a) // true,值相等,对象地址相等

    //经过了装箱,创建了两个不同的对象
    val boxedA: Int? = a
    val anotherBoxedA: Int? = a

    //虽然经过了装箱,但是值是相等的,都是10000
    println(boxedA === anotherBoxedA) //  false,值相等,对象地址不一样
    println(boxedA == anotherBoxedA) // true,值相等

类型转换
由于不同的表示方式,较小类型并不是较大类型的子类型,较小的类型不能隐式转换为较大的类型。 这意味着在不进行显式转换的情况下我们不能把 Byte 型值赋给一个 Int 变量。

//每种数据类型都有下面的这些方法,可以转化为其它的类型:
        //toByte(): Byte
        //toShort(): Short
        //toInt(): Int
        //toLong(): Long
        //toFloat(): Float
        //toDouble(): Double
        //toChar(): Char
        val b: Byte = 1 // OK, 字面值是静态检测的
        val i: Int = b.toInt() //

数组定义:

 //类Array,还有ByteArray, ShortArray, IntArray,用来表示各个类型的数组,省去了装箱操作,因此效率更高,其用法同Array一样
    var x: IntArray = intArrayOf(4, 2, 3)
    for (value in x) {
        println(value)  //value是数组的具体值,输出4,2,3
    }
    
    for (i in x.indices) {
        println(x[i])  //i是数组的下标,从0开始
    }

字符串格式模板""" “”",由三个成对双引号包裹,输出字符串原有的格式排版:

val text = """
    |多行字符串
    |菜鸟教程
    |多行字符串
    |Runoob
    """
    println(text)
    //输出后的内容
    |多行字符串
    |菜鸟教程
    |多行字符串
    |Runoob
    

for循环控制:
for 循环可以对任何提供迭代器(iterator)的对象进行遍历

//对数组进行迭代
var x: IntArray = intArrayOf(4, 2, 3)
    for (value in x) {
        println(value)  //value是数组的具体值,输出4,2,3
    }
    
    for (i in x.indices) {
        println(x[i])  //i是数组的下标,从0开始
    }
    //对集合进行迭代
    var items = listOf("张三","李四","王五")
    for (value in items) {
        println(value)
    }
    for (i in items.indices) {
        println(items[i])
    }

class Runoob {  // 类名为 Runoob
    // 大括号内是类体构成
}

类的成员变量:
类的属性可以用关键字 var 声明为可变的,否则使用只读关键字 val 声明为不可变。

class Runoob {
	//必须初始化值
    var name: String =""
    var url: String =""
    var city: String =""
}

类的构造器
Koltin 中的类可以有一个 主构造器,以及一个或多个次构造器,主构造器是类头部的一部分,位于类名称之后:

//constructor代表主构造器
class Person constructor(firstName: String) {}

如果主构造器没有任何注解,也没有任何可见度修饰符,那么constructor关键字可以省略。

class Person(firstName: String) {
}

实例:

class Person{
    var name : String =""
        get() = field.toUpperCase() // 将变量赋值后转换为大写
        set
    var no : Int =0
        get() = field
        set(value) {
            if (value<10){      // 如果传入的值小于 10 返回该值
                field = value
            }else{              // 如果传入的值大于等于 10 返回 -1
                field = -1
            }
        }
    var heiht: Float = 145.4f
    private set
}

调用:

var person: Person = Person()

    person.name = "wang"

    println("lastName:${person.name}")

    person.no = 9
    println("no:${person.no}")

    person.no = 20
    println("no:${person.no}")
    //输出内容为:
    //lastName:WANG
	//no:9
	//no:-1

主构造器
如果构造器有注解,或者有可见度修饰符,这时constructor关键字是必须的,注解和修饰符要放在它之前。
实例
创建一个 Runoob类,并通过构造函数传入网站名:

class Runoob constructor(name:String) {
    // 大括号内是类体构成
    var url: String = "http://www.runoob.com"
    var country: String = "CN"
    var siteName = name

    init {
        println("初始化网站名: ${name}")
    }

    fun printTest() {
        println("我是类的函数")
    }
}
//调用:
 val runoob =  Runoob("菜鸟教程")
    println(runoob.siteName)
    println(runoob.url)
    println(runoob.country)
    runoob.printTest()

输出结果:
在这里插入图片描述
次构造函数
类也可以有二级构造函数,需要加前缀 constructor。
如果类有主构造函数,每个次构造函数都要,或直接或间接通过另一个次构造函数代理主构造函数。在同一个类中代理另一个构造函数使用 this 关键字:

class Person(val name: String) {
    constructor (name: String, age:Int) : this(name) {
        // 初始化...
    }
}

次级构造函数实例:

class Student constructor(name : String) {
    // 大括号内是类体构成
    var url: String = "http://www.runoob.com"
    var country: String = "CN"
    var siteName = name

    init {
        println("初始化网站名:${name}")
    }
    //次构造函数
    constructor(name:String,alexa:Int):this(name){
        println("Alexa 的排名是:${alexa}")
    }
    fun printTest(){
        println("我是类的函数")
    }
}

//调用:
val student = Student("菜鸟教程",1)
    println(student.siteName)
    println(student.url)
    println(student.country)
    println(student.printTest())

输出结果:
在这里插入图片描述
嵌套类:
类嵌套在其他类中,看以下实例:

class Outer {  //外部类
    private var bar: Int = 1;
    class Nested{ //嵌套类
        fun foo()=2
    }
}
//调用:
var demo = Outer.Nested().foo() // 调用格式:外部类.嵌套类.嵌套类方法/属性
    println("调用嵌套类的成员函数:"+demo)

内部类
内部类使用 inner 关键字来表示。
内部类会带有一个对外部类的对象的引用,所以内部类可以访问外部类成员属性和成员函数。
为了消除歧义,要访问来自外部作用域的 this,我们使用this@label,其中 @label 是一个 代指 this 来源的标签。

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

//调用:
 var demo = Outer().Inner().foo() // 调用格式:外部类.嵌套类.嵌套类方法/属性
    println(demo)
    var demo1 = Outer().Inner().innerTest()
    println(demo1)   // 内部类可以引用外部类的成员,例如:成员属性

类的继承
Kotlin 中所有类都继承该 Any 类,它是所有类的超类,对于没有超类型声明的类是默认超类:

class Example // 从 Any 隐式继承

如果一个类要被继承,可以使用 open 关键字进行修饰。

open class Base(p: Int)           // 定义基类

class Derived(p: Int) : Base(p)

子类有主构造函数
如果子类有主构造函数, 则基类必须在主构造函数中立即初始化。:

open class Person(var name:String,var age:Int){ //基类,带属性成员name和age
}

class Student (name:String,age:Int,var no : String,var score: Int) : Person(name,age){ //子类

}
//调用:
val s = Student("Runoob",18,"S123456",80)
    println("姓名:${s.name}")
    println("年龄:${s.age}")
    println("学号:${s.no}")
    println("成绩:${s.score}")

子类没有主构造函数
如果子类没有主构造函数,则必须在每一个二级构造函数中用 super 关键字初始化基类,或者在代理另一个构造函数。初始化基类时,可以调用基类的不同构造方法。

class Student : Person {

    constructor(ctx: Context) : super(ctx) {
    } 

    constructor(ctx: Context, attrs: AttributeSet) : super(ctx,attrs) {
    }
}

实例:


/**
 * 用户基类
 */
open class Person(var name:String){
    /**
     * 次级构造函数
     */
    constructor(name: String,age:Int):this(name){
        //初始化
        println("-------基类次级构造函数---------")
    }
}


/**
 * 子类继承 Person类
 */
class Student : Person{
    /**
     * 次级构造函数
     */
    constructor(name: String,age:Int,no:String,score:Int):super(name,age){
        println("-------继承类次级构造函数---------")
        println("学生名: ${name}")
        println("年龄: ${age}")
        println("学生号: ${no}")
        println("成绩: ${score}")
    }
}
//调用:
Student("Runoob",18,"S123456",80)

输出:
在这里插入图片描述
重写
在基类中,使用fun声明函数时,此函数默认为final修饰,不能被子类重写。如果允许子类重写该函数,那么就要手动添加 open 修饰它, 子类重写方法使用 override 关键词

/**
 * 用户基类
 */
open class Person{
   open fun study(){  //open修饰 允许子类重写
       println("正在学习")
   }
}

/**
 * 子类继承 Person类
 */
class Student : Person() {
    override fun study() {  //override重写父类方法
        super.study()  //此处代码会先调用父类方法
        println("我毕业啦")
    }
}

//调用:
 val student = Student()
    student.study()

输出:
在这里插入图片描述
如果有多个相同的方法(继承或者实现自其他类,如A、B类),则必须要重写该方法,使用super范型去选择性地调用父类的实现。

open class A {
    open fun f(){
        println("A")
    }
    fun a(){
        println("a")
    }
}

interface B {
    fun f(){
        println("B")  //接口的成员变量默认是open的
    }
    fun b(){
        println("b")
    }
}

class C():A(),B {
    override fun f() {
        super<A>.f() //调用 A.f()
        super<B>.f()  //调用 B.f()
    }
}
//调用:
 val c = C()
    c.f() //输出 A,B
    

Kotlin 扩展
Kotlin 可以对一个类的属性和方法进行扩展,且不需要继承或使用 Decorator 模式。
扩展是一种静态行为,对被扩展的类代码本身不会造成任何影响。

扩展函数
扩展函数可以在已有类中添加新的方法,不会对原类做修改,扩展函数定义形式:

fun receiverType.functionName(params){
    body
}

receiverType:表示函数的接收者,也就是函数扩展的对象
functionName:扩展函数的名称
params:扩展函数的参数,可以为NULL

class User(var name:String){
}
fun User.print(){
    println("用户名是: ${name}")
}
//调用:
val user = User("张三")
    user.print() //输出 用户名是:张三

案例,为 MutableList 添加一个swap 函数:

// 扩展函数 swap,调换不同位置的值
    fun MutableList<Int>.swap(index1: Int, index2: Int) {
        val tmp = this[index1]     //  this 对应该列表
        this[index1] = this[index2]
        this[index2] = tmp
    }

    val l = mutableListOf(4, 2, 3)
    // 位置 0 和 2 的值做了互换
    l.swap(0, 2) // 'swap()' 函数内的 'this' 将指向 'l' 的值

    println(l.toString()) //输出[3, 2, 4]

扩展函数是静态解析的
扩展函数是静态解析的,并不是接收者类型的虚拟成员,在调用扩展函数时,具体被调用的的是哪一个函数,由调用函数的的对象表达式来决定的,而不是动态的类型决定的:

open class C

class D: C()

fun C.foo() = "c"   // 扩展函数 foo

fun D.foo() = "d"   // 扩展函数 foo

fun printFoo(c: C) {
    println(c.foo())  // 类型是 C 类
}

fun main(arg:Array<String>){
    printFoo(D())
}

实例执行输出结果为:

c

若扩展函数和成员函数一致,则使用该函数时,会优先使用成员函数。

class C {
    fun foo() { println("成员函数") }
}

fun C.foo() { println("扩展函数") }

fun main(arg:Array<String>){
    var c = C()
    c.foo()
}

实例执行输出结果为:

成员函数

扩展一个空对象
在扩展函数内, 可以通过 this 来判断接收者是否为 NULL,这样,即使接收者为 NULL,也可以调用扩展函数。例如:

fun Any?.toString(): String {
    if (this == null) return "null"
    // 空检测之后,“this”会自动转换为非空类型,所以下面的 toString()
    // 解析为 Any 类的成员函数
    return toString()
}
fun main(arg:Array<String>){
    var t = null
    println(t.toString())
}

实例执行输出结果为:

null

Kotlin 泛型
泛型,即 “参数化类型”,将类型参数化,可以用在类,接口,方法上。
与 Java 一样,Kotlin 也提供泛型,为类型安全提供保证,消除类型强转的烦恼。
声明一个泛型类:

/**
 * 创建box类的泛型
 */
class Box<T>(t:T) {
    var value = t
}

实例:

/**
 * 创建box类的泛型
 */
class Box<T>(t:T) {
    var value = t
}

val boxInt = Box<Int>(10)
val boxString = Box<String>("传入泛型String值")

println(boxInt.value)
println(boxString.value)

输出:

10
传入泛型String值

定义泛型类型变量,可以完整地写明类型参数,如果编译器可以自动推定类型参数,也可以省略类型参数。
Kotlin 泛型函数的声明与 Java 相同,类型参数要放在函数名的前面:

fun <T> boxIn(value: T) = Box(value)

// 以下都是合法语句
val box4 = boxIn<Int>(1)
val box5 = boxIn(1)     // 编译器会进行类型推断

在调用泛型函数时,如果可以推断出类型参数,可以省略泛型参数。
以下实例创建了泛型函数 doPrintln,函数根据传入的不同类型做相应处理:

 	val age = 23
    val value = "runoob"
    val bool = true
    
    doPrintln(age)    // 整型
    doPrintln(value)   // 字符串
    doPrintln(bool)   // 布尔型

/**
 * 泛型函数
 */
fun <T> doPrintln(content: T) {
    when (content) {
        is Int -> println("整型数字为 $content")
        is String -> println("字符串转换为大写:${content.toUpperCase()}")
        else -> println("T 不是整型,也不是字符串")
    }
}

输出:

整型数字为 23
字符串转换为大写:RUNOOB
T 不是整型,也不是字符串

…未完待续

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值