前言
本文章只是用于记录学习,所以部分地方如果有错误或者理解不对的地方,麻烦请指正。本篇为 csdn 原文章 转移修改版 原文章
工具
- android 开发的话 可以使用 android studio ,在新建项目的时候记得勾选 supper kotlin 就可以了,和jni 开发操作相似的。进入android studio之后如果是 3.0 以后的版本,都是自带kotlin 插件的,如果是 as3.0一下的版本则需要在 File /setting / plugins / 搜索 kotlin 安装重启。
- 平时跟我一样在学习的话,可以使用idea ,新建kotlin 项目,在里边联系就可以了。
1. HelloWorld 及 包的声明
在Kotlin中定义包与Java有点不同,在Kotlin中目录与包结构无需匹配,
Kotlin的源码可以在磁盘上的任意位置。
// 包格式 和 java 一致
package com.ymc.hellokotlin
fun main(args: Array<String>) {
println("Hello world")
println(max(2,3))
}
fun max(a:Int ,b:Int):Int{
return if(a>b) a else b;
}
1. main 函数不需要在class 中就可以运行
2. fun 代表一个函数,后边紧跟函数名称,参数列表和返回值类型
3. 参数实现写 参数名称 然后冒号隔开,再写参数类型(和java 相反)
4. 函数的返回值是在后边的(和java刚好相反的)当然 有返回值 也可以不写返回类型(前提是:只有表达式体 函数返回类型可以省略,如果是代码块体函数就必须要 写明函数返回类型),因为kotlin 通过 类型推导 也是可以知道返回值类型的
5. system.out.println 被包装为 println
6. 在行末可以省略 分号 (类似 js)
7. 看到max函数中 if类似于三元表达式 kotlin中,if 是有结果值的表达式
8. 如果返回值 类似于 java 中的 void 则可以写成 :Unit ,当然也可以省略不写
在kotlin 中,除了部分循环(for do 和 do/while)大多控制结构都是表达式,是有返回值的。另一方面 java 中的赋值语句为表达式,而kotlin 中则为语句。
与Java定义包名一样,在源文件的开头定义包名:但是不同的是,包名和文件夹路径可以不一致:源文件可以放在项目的任意位置,当然也不建议这样搞,自己何苦为难自己。。。
2. 变量
考虑到kotlin 的变量声明是可以省略 类型的,所以kotlin 变量声明有别于java ,kotlin 变量声明顺序为 关键字 变量名称 类型(可不加),如果变量没有初始化 则需要明确表明 变量类型。
常量与变量都可以没有初始化值,但是在引用前必须初始化编译器支持自动类型判断,即声明时可以不指定类型,由编译器判断。如果不在声明的时候初始化则必须提供变量的类型
val name = "ymc"
val age = 23
val age1 : Int = 23
val age2 :Int
age2 = 24
val :不可变引用 ,在val声明变量后不能再初始化之外再次赋值(java final)
var :可变引用 , 该类型变量可以随便赋值
*** 官方推荐** 尽量使用val 声明变量,使程序更接近函数式编程风格
1、可变变量的定义: var 关键字
var <变量名> : <变量类型> = <初始值>
var sum: Int = 3
sum = 8
//由于编译支持类型推导可以省略Int类型
var sum = 3
sum = 8
2、不可变变量的定义: val 关键字, 不能进行二次赋值,类似Java中的final类型
val <常量名> : <常量类型> = <初始值>
val sum: Int //没有赋值初始化之前必须指定类型
sum = 5
已知值的属性可以使用 const 修饰符标记为 编译期常量。需要满足如下几种条件 (类似 java 中的 constanUtil 中的 常量值)
- 位于顶层或者是 object 的一个成员
- 用 String 或原生类型 值初始化
- 没有自定义 getter
const val SUBSYSTEM_KEY: String = "key"
@Deprecated(SUBSYSTEM_KEY) fun foo() { …… }
3 .字符串模版
println("Hello world $name") // $变量
println("Hello world ${age[0]}") // ${变量}
println("Hello world " + name) // 原来的方法也是可以继续使用的
var a = 1
a = 2
var s1 = "a is $a"
val s2 = "${s1.replace("is", "was")}, but now is $a"
4. 类和属性
4.1 类
接下来 我们比较一下 java 和 kotlin 中类的写法的不同
java
public class DemoBean {
private final String name;
public DemoBean(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
kotlin
class DemoBean(val name: String)
如果您跟我一样也是落后的kotlin初学者,我们可以在日常生活中还是以 java 语言开发为主 ,如果需要看kotlin 的效果的时候,我们可以将java 代码复制到 kt文件中,idea会自动提示我们转换。
4.2 属性
类 ,也就是我们将数据和处理数据的代码封装成一个单一的实体。
class Person{
var name :String = "ymc" // 可读可写
val isMarried : Boolean = false // 只读
}
上段代码中 isMarried 会生成一个字段,一个getter ,而 name 则会生成 一个 getter和一个 setter 。
kotlin 在你声明属性的时候,你就声明了对应的访问器,默认的访问器 就是返回值的 getter 和 更新数值的 setter ,kotlin 会暴漏一个 getName 方法,当然我们也可以自定义访问器。
fun main(args: Array<String>) {
var person = Person()
println(person.name +";"+ person.isMarried )
}
可以看到我们直接调用而不需要get,感觉很像js...
4.3 自定义访问器
class Person{
var name :String = "ymc"
var sex : Int = 0; // 0 为女性 1为男性
val isMarried : Boolean = false
val isBoy :Boolean
get() {
return if(sex==1) true else false
}
}
我们将Person 添加 sex 和 isboy 属性,重写getter ,这样就可以做到自定义访问器。
如果 我们设置 属性为 val 但是通过自定义 getter 修改属性那么 属性会修改么?
fun main(args: Array<String>) {
val name = "Hello Kotlin"
name = "Hello Java"
}
如果单纯的 修改 则会报错
Error:(8, 5) Kotlin: Val cannot be reassigned
接下来我们通过 自定义访问器 看看
class RandomNum {
val num: Int
get() = Random().nextInt()
}
fun main(args: Array<String>) {
println("the num is ${RandomNum().num}")
}
the num is -1251923160
the num is -1527833641
总结: 由以上的例子可以说明假设一是成立的,在Kotlin中的val修饰的变量不能说是不可变的,而只能说仅仅具有可读权限。
4.4 备用字段
kotlin 中并不允许使用 字段,这个时候 我们就可以使用备用字段,比如下段 代码,起到局部变量的作用。
//初始化值会直接写入备用字段
var counter = 0
get() = field // field可以理解为自己本身
set(value) {
if (value >= 0)
field = value
}
// 这种情况并不需要备用字段,所有不会生成备用字段
val isEmpty: Boolean
get() = this.size == 0
注意:field标识符只允许在属性的访问器函数内使用.
4.5 延迟初始化属性和变量
属性声明为非空类型必须在构造函数中初始化,为处理这种情况,你可以用 lateinit 修饰符标记该属性:
public class MyTest {
lateinit var subject: TestSubject
@SetUp fun setup() {
subject = TestSubject()
}
@Test fun test() {
subject.method() // 直接解引用
}
}
这样的话,我们就可以不用再构造函数的时候对其进行初始化,后续在哪里需要 调用 setup就可以。
5. null检查机制
Kotlin的空安全设计对于声明可为空的参数,在使用时要进行空判断处理,有两种处理方式,字段后加!!像Java一样抛出空异常,另一种字段后加?可不做处理返回值为 null或配合?:做空判断处理
//类型后面加 ? 表示可为空
var age: String? = "23"
//字段后面加 "!!" ,如果为null则抛出空指针异常
val ages = age!!.toInt()
//字段后面加 ”?“ 如果为null不做处理返回 null
val ages1 = age?.toInt()
//使用 ”?:“ 表示age为null返回-1
val ages2 = age?.toInt() ?: -1
kotlin 中如果 数值 或 返回值可以为 空的时候 则可以在 类型后边加上 ?
fun getStringLength(obj: Any): Int? {
if (obj is String) {
// `obj`在这个分支中自动转换为`String`类型
return obj.length
}
// `obj`仍然是`Any`类型
return null
}
fun getStringLength(obj: Any): Int? {
// `obj`在这个分支中自动转换为`String`类型
if (obj !is String) return null
return obj.length
}
该方法返回值可以为 null 也可以是 int 类型 字符串的长度,在判断中我们有看到了新的 词语 is ,is 表达式主要检查 表达式或者值 的类型是否是 is 后边的类型,如果是 则会进行自动转换,如果不是则 仍然保持原来的数据类型。
上段代码中我们可以看到 kotlin 和 java 的类型转换的差别,java 使用instanceOf 来判断类型后,如果要转型需要 显式将该类型转换为我们比较的类型,而 kotlin 中 使用 is 检查过 数据后,如果类型正确 则会 智能转型,这一步是编译器自动帮我们完成的。
当然如果我们需要使用 显式转换的时候 可以使用 as 表达式,(val n = A as Num)
网友评论