IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> kotlin基础学习笔记之第二章 -> 正文阅读

[移动开发]kotlin基础学习笔记之第二章

目录

? ? ? ? 表达式函数体

? ? ? ? 变量

? ? ? ? 字符串模板

? ? ? ? 类和属性

? ? ? ? 枚举和when

? ? ? ? if和when

? ? ? ? 迭代

? ? ? ? 异常

1、表达式函数体

fun main(args: Array<String>) {
    println("hello world")
    println(max1(3, 5))
    println(max2(7, 5))
    println(max3(7, 5))
}

fun max1(a: Int, b: Int): Int {
    return if (a>b) a else b
}

//当代码式函数体内只有单个表达式时,可以用这个表达式作为完整的函数体,并去掉话括号和return语句
//在kotlin中if是表达式,而不是语句。语句和表达式的区别在于:表达式有值,并且能作为另一个表达式的一部分使用
//而语句总是包围着它的代码块中的顶层元素,并且没有自己的值。
fun max2(a: Int, b: Int): Int = if (a > b) a else b

//表达式体函数的返回类型可以省略,因为编译器会分析作为函数体的表达式,并
//把它的类型作为函数的返回类型。
//注意:只有表达式体的函数可以省略返回类型
fun max3(a: Int, b: Int)= if (a > b) a else b

2、变量

? ? ? ? 变量分为可变变量和不可变变量:

? ? ? ? val (来自value)不可变引用,使用val声明的变量不能在初始化之后再次赋值。它对应java的final变量;

? ? ? ? var (来自variable)可变引用,这种变量的值是可以改变的,它对应java的普通(非final)的java变量;

? ? ? ? 在定义了val变量的代码块执行期间,val变量只能进行唯一一次初始化。但是,如果编译器能确保只有唯一一条初始化语句被执行,可以根据条件使用不同的值来初始化它:

fun main() {
    val message: String
    var flag: Boolean = false
    if (flag) message = "i'm false" else message = "i'm true"
}

? ? ? ? 注意:尽管val引用自身是不可变的,但是它指向的对象是可变的。

val list = arrayListOf("liu", "qin", "hou")
list.add("love")

? ? ? ? 注意:即使var关键字允许变量改变自己的值,但它的类型却是改变不了的。

var answer = 42
answer = "no answer" //error:Type mismatch

? ? ? ? 如果需要在变量中存储不匹配的类型,必须手动把值转换或强制转换到正确的类型。

3、字符串模板

val name = if(args.size > 0) args[0] else "Kotlin"
println("hello $name")

? ? ? ? kotlin可以在字符串字面值中引用局部变量,只需要在变量名称前面加上字符$。

? ? ? ? 如果要在字符串中使用$字符,则需要对它转义:println("\$x")会打印$x,并不会把x解释成变量的引用。

? ? ? ? 还可以引用复杂的表达式,而不是仅限于简单的变量名称,只需要把表达式用花括号括起来:

if (args.size > 0) {
    println("hello ${args[0]}")
}

? ? ? ? 还可以在双引号中直接嵌套双引号,只要它们处在某个表达式的范围内(即花括号内)

println("hello ${if (args.size > 0) args[0] else "Kotlin"}")

? ? ? ? 注意:字符串模板其实其背后的原理是,编译器在编译后创建了一个StringBuilder对象,并把常量部分和变量部分附加上去。

4、类和属性

? ? ? ? 首先来看一个简单的JavaBean类Person,目前它只有一个属性,name。

java方式的写法

public class Person {
    private String name;
    
    public Person(String name) {
        this.name = name;
    }
    
    public String getName() {
        return this.name;
    }
}

Kotlin方式的写法(可以看到其和java方式的写法能节省很多代码)

class Person(val name: String)

? ? ? ? 这种类(只有数据没有其他代码)通常被叫做值对象。

? ? ? ? 注意,从java到kotlin的转换过程中public修饰符消失了。在kotlin中,public是默认的可见性,所以你能省略它。

? ? ? ? 属性

? ? ? ? 在java中,字段和其访问器的组合常常叫做属性。在kotlin中,属性是头等的语言特性,完全代替了字段和访问器方法。在类中声明一个属性和声明一个变量一样:使用val和var关键字,声明val的属性是只读的,而var属性是可变的。

? ? ? ? 对于那些在java中定义的类,一样可以使用kotlin的属性语法。java中的getter可以被当成val属性在kotlin中访问,而一对getter/setter可以被当成var属访问。例如,如果一个java类定义了两个名称为getName和setName的方法,就把他们当成名称为name的属性访问。如果类定义了isMarried和setMarried方法,对应kotlin的属性就是isMarried。

? ? ? ? 自定义访问器????????

class Rectangle(val height: Int, val width: Int) {
    val isSquare: Boolean
        get() {
            height == width
        }
}

? ? ? ? 属性isSquare不需要字段来保存它的值,它只有一个自定义实现的getter,它的值是每次访问属性的时候计算出来的。? ? ? ? ? ? ?

? ? ? ? 注意:不需要使用带花括号的完整语法,也可以使用下面简洁写法

class Rectangle(val height: Int, val width: Int) {
    val isSquare: Boolean
        get() = height == width
}

? ? ? ? kotlin源码布局:目录和包

? ? ? ? kotlin和java有相似的包概念:每一个kotlin文件都能以一个package语句开头,而文件中定义的所有声明(类、函数及属性)都会被放在这个包中。如果其他文件中定义的声明也有相同的包,这个文件可以直接使用他们;如果包不同,则需要导入他们。? ? ? ??

5、枚举和when

? ? ? ? 首先声明一个简单的枚举类

enum class Color {
    RED, GREEN, YELLOW, ORANGE
}

? ? ? ? 在kotlin中enum是一个所谓的软关键字:只有当它出现在class 前面时才有特殊的意义,在其他地方可以把它当做普通的名称使用。

? ? ? ? 和java一样,枚举并不是值的列表。可以给枚举类声明属性和方法。

enum class Color1(val r: Int, val g: Int, val b: Int) {
    RED(255, 0 , 0), 
    GREEN(0, 255, 0), 
    YELLOW(22,22,22), 
    ORANGE(33, 33, 33);
    
    fun rgb() = (r * 256 + g) * 256 +b 
}

? ? ? ? kotlin中的when结构比java中的switch强大很多,switch要求必须使用常量(枚举常量、字符串、或者数字字面值)作为分支条件。和switch不一样,when允许使用任何对象。

fun mix(c1: Color, c2: Color) = when (setOf(c1, c2)) {
    setOf(Color.RED, Color.GREEN) -> Color.ORANGE
    setOf(Color.RED, Color.ORANGE) ->Color.YELLOW
    else -> throw Exception("dirty color")
}

? ? ? ? 使用不带参数的when

fun mixOptimized(c1: Color, c2: Color) = when {
    setOf(Color.RED, Color.GREEN) == Color.ORANGE -> Color.ORANGE
    setOf(Color.RED, Color.ORANGE) == Color.YELLOW -> Color.YELLOW
    else -> throw Exception("dirty color")
}

? ? ? ? 如果没有给when表达式提供参数,分支条件就是任意的布尔表达式。

5、智能转换:合并类型检查和转换

interface Expr {
}

class Num(val vaule: Int): Expr

class Sum(val left: Expr, val right: Expr): Expr

fun main() {
    println(eval(Sum(Sum(Num(1), Num(2)), Num(3))))
}

fun eval(e: Expr):Int {
    if (e is Num) {
        //显示地转换成类型Num是多余的,编译器识别出并把“as Num”置灰了
        val n = e as Num
        return n.vaule
    }
    if (e is Sum) {
        //变量e被智能地转换了类型
        return eval(e.left) + eval(e.right)
    }
    throw IllegalArgumentException("Unknown expression")
}

? ? ? ? 在kotlin中使用is检查来判断一个变量是否是某种类型。is检查和java中的instanceOf相似。但是在java中,如果您已经检查过一个变量是某种类型并且需要把它当做这种类型来访问其成员时,在instanceOf检查后还需要显示地加上类型转换。如果最初的变量会使用超过一次,常常选择把类型转换的结果存储在另一个单独的变量里。

? ? ? ? 在kotlin中,编译器帮您完成了这些工作,如果您坚持过一个变量是某种类型,后面就不再需要转换它,可以直接把它当做您检查过的类型使用。事实上编译器为您执行了类型转换,我们把这种行为称为智能转换。

? ? ? ? 智能转换只在变量经过is检查且之后不再发生变化的情况下有效。

? ? ? ? kotlin使用as关键字来表示到特定类型的显示转换。

6、if和when

fun eval(e: Expr): Int = 
        if (e is Num) {
            e.vaule
        } else if (e is Sum) {
            eval(e.left) + eval(e.right)
        } else {
            throw IllegalArgumentException("Unknown expression")
        }

? ? ? ? 如果if分支中只有一个表达式,花括号是可以省略的。如果if分支是一个代码块,代码块中的最后一个表达式会被作为结果返回。

? ? ? ? 可以进一步打磨代码,使用when来重写

fun eval(e: Expr): Int =
        when (e) {
            is Num -> e.vaule
            is Sum -> eval(e.left) + eval(e.right)
            else -> throw IllegalArgumentException("Unknown expression")
        }

? ? ? ? if和when都可以使用代码块作为分支体,这种情况下,代码块中的最后一个表达式就是结果。

? ? ? ? 规则“代码块中最后的表达式就是结果”,在所有使用代码块并期望得到一个结果的地方成立。这个规则对try主体和catch子句也有效。在lambda表达式中也有效。但是在2.2节我们提到,这个规则对常规函数不成立,一个函数要么具有不是代码块的表达式函数体,要么是具有包含显示return语句的代码块函数体。

7、迭代

? ? ? ? 迭代数字:区间和数列

? ? ? ? 在kotlin中没有常规的java for循环,在这种循环中,先初始化变量,在循环的每一步更新它的值,并在满足某个限制条件时退出循环。为了替代这种最常见的循环用法,kotlin使用可区间的概念。

? ? ? ? 区间本质上是两个值的间隔,这两个值通常是数字:一个起始值,一个结束值,使用..运算符来表示区间:

val oneToTen = 1 .. 10

? ? ? ? 注意kotlin区间是包含的或者闭合的,意味着第二个值始终是区间的一部分。

? ? ? ?使用downTo来表示递减地遍历,使用step来表示步长。

for (i in 100 downTo 1 step 2) {
    ...
}

? ? ? ? until函数可以构建一个不包含结束值的区间,下面的区间范围为[0~99]。

for (i in 0 until 100)

? ? ? ? 迭代map

fun test() {
    val binaryReps = TreeMap<Char, String>()
    for (i in 'A'..'Z') {
        val binary = Integer.toBinaryString(i.toInt())
        binaryReps[i] = binary
    } 
    for ((letter, binary) in binaryReps) {
        println("$letter = $binary")
    }
    
}

? ? ? ? 使用字符区间迭代从A到Z之间的字符。迭代map,把键和值赋值给两个变量。

? ? ? ? 在kotlin中可以根据键来访问和更新map的简明语法:可以使用map[key]读取值,并使用map[key]=newValue设置值,而不需要使用get和put。

? ? ? ? 使用in检查集合和区间内的成员

? ? ? ?使用in运算符来检查一个值是否在区间内,或者使用它的逆运算!in来检查这个值是否不在区间内。

? ? ? ? 注意:区间不仅限于字符。假如有一个支持实例比较操作的任意类(实现了java.lang.Comparable接口),你就能创建这种类型的对象的区间。如果是这样的区间,并不能列举出这个区间中的所有对象。想想这种情况,例如是否可以列举出“java”和“kotlin”之间所有的字符串?答案是不能。但是仍然能使用in运算符检查一个其他的对象是否属于这个区间。?

8、异常

? ? ? ? 和java不同的是,kotlin中throw结构是一个表达式,能作为另外一个表达式的一部分使用:

    val percentage =
            if (number in 0..100) 
                number
            else 
                throw IllegalArgumentException("xxxx")

? ? ? ? 和java最大的区别是throws子句没有出现在代码中:如果用java来写这个函数,你会显示地在函数声明后写上throws IOException。你需要这样做的原因是因为IOException是一个受检异常。在java中,这种异常必须显示地处理。必须声明你的函数能抛出的所有受检异常。如果调用另外一个函数,需要处理这个函数的受检异常,或者声明你的函数也能跑出这些异常。

? ? ? ? 和其他许多现代JVM语言一样,kotlin并不区分受检异常和未受检异常。不用指定函数抛出的异常,而且可以处理也可以不处理异常。这种设计是基于java中使用异常的实践做出的决定。经验显示这些java规则常常导致许多毫无意义的重新抛出或者忽略异常的代码,而且这些规则不能总是保护你免受可能发生的异常。

//不必显示地指定这个函数可能抛出的异常
fun readNumber(reader :BufferedReader): Int? {
    try {
        var line = reader.readLine()
        return Integer.parseInt(line)
    } catch (e : NumberFormatException) {
        return null
    } finally {
        reader.close()
    }
}

? ? ? ? try作为表达式????????

? ? ? ? kotlin中的try关键字就像if和when一样,引入了一个表达式,可以把它的值赋值给一个变量。不同于if,你总是需要使用花括号把语句主体括起来。和其他语句一样,如果其主体包含多个表达式,那么整个try表达式的值就是最后一个表达式的值。

fun readNumber2(reader :BufferedReader): Int? {
    val number = try {
        Integer.parseInt(reader.readLine())
    } catch (e: NumberFormatException) {
        null
    }
    return number
}

? ? ? ? 如果一个try代码块执行一切正常,代码块中最后一个表达式就是结果。如果捕获到了一个异常,相应catch代码块中最后一个表达式就是结果。

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-10-17 12:46:08  更:2022-10-17 12:50:18 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/20 1:06:26-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码