前言
kotlin官网 (中文版)和kotlin教程学习教程的笔记。
一、关于环境配置的建议
1.建议大家直接用Android Studio3.0+来进行开发,新建项目,勾选support kotlin即可完成相关配置,并进行kotlin的开发。
- 比较java和kotlin的区别,使用command+shift+a打开action输入弹窗,输入convert即可将java转换为kotlin。即可看到如下kotlin代码:
class MainActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
二、类与函数
- 类:默认继承Any(类似于Object)。我们写的类只可以继承那些明确声明open或者abstract的类。
open class Person(name:String,age: Int)
class Teacher(name: String, age:Int) : Person(name, age)
- 函数:Kotlin 里没有 void,所有函数都有返回类型
//返回最大值
fun maxOf(a: Int, b: Int=0) = if (a > b) a else b
//可以直接maxOf(1)这样相当于调用maxOf(1,0)
//没有返回值返回Unit,Unit概念上相当于Void,当然也可以不写
fun showMsg(msg:String){
println(msg)//在logcat中可看到打印出的内容
}
- 覆盖的规则
open class A {
open fun f() { print("A") }
fun a() { print("a") }
}
interface B {
var name: String //属性在接口中不可以被赋值,需要子类重写
fun f() { print("B") } // 接口的成员默认是 'open' 的
fun b() { print("b") }
}
class C() : A(), B {
override var name: String = "c"
// 编译器要求 f() 方法必须覆盖:
override fun f() {
super<A>.f() // 调用 A.f()
super<B>.f() // 调用 B.f() }
}
- 构造函数
(1). 主构造函数
class Person(name:String,age:Int){
init{
println("My name is $name, I am $age years old ") //相当于构造函数中的内容
}
}
//主构造函数为private
class Person private constructor(name:String,age:Int){
}
(2). 次级构造函数
class Person( name: String) {
init {
println("person init $name")
}
constructor(name: String, age: Int) : this(name) {
println("My name is $name, I am $age years old ")
}
}
Person("a")
Person("b", 1)
三、基本类型与变量
-
$符号调用表达式
val & var :val->只读变量,相当于final。var->可变变量。
val str = "$s.length is ${s.length}" // 计算结果为 "abc.length is 3"
建议自己算一下O(∩_∩)O~:- ?的使用 --进行null检查
var s:String?=null
println(s?.length) // s为null输出null, s不为null,输出长度。
fun parseInt(data:String):Int?{ // data不可为null
return data.toIntOrNull()
}
//----
fun parseInt(data:String?):Int?{ // data可以为null
return data?.toIntOrNull()
}
val data = ...
data?.let {
... // 这个代码段将在 data 不为 null 时执行
}
var s: String? = null
println(s ?: "null string") //输出null string
val files = File("Test").listFiles()
println(files?.size ?: "empty") // If not null … else 的简写表达方式
- 使用is判断类型,相当于instanceOf, 使用as类型转换
// 在 `&&` 运算符的右侧, `obj` 的类型会被自动转换为 `String`
if (obj is String && obj.length > 0) {
return obj.length
}
(obj as String).length //强制转换
- 循环
- while循环不变,for循环有一点变化,如下:
val items = listOf("a", "b", "c")
for (item in items) {
print(item+" ")
}
//apple banana kiwi
val items = listOf("apple", "banana", "kiwi")
for (index in items.indices) {
println("item at $index is ${items[index]}") //index为下标
}
- 循环中的返回与跳转:
loop@ for (i in 1..100) {
for (j in 1..100) {
if (...) break@loop
}
} //将直接跳出最外层循环
fun loopCheck(){
(1..10)
.forEach list@ { if (it==1) return@list}
println("touch this")
} //会输出touch this,如果将list@标签去掉,就不会输入任何内容
return@a 1 //返回到标签 @a 处, 返回值为 1
- 判断
(1) when,相当于switch
val s = when(x){
is Int -> "Int instance"
is String -> "String instance"
else -> throw UnsupportedOperationException("Not valid type") //在Kotlin中, throw 和 try 都是表达式,因此它们可以被赋值给一个变量。
}
(2) in,相当于contains
val x = 10
val y = 9
if (x in 1..y+1) { //include y+1
println("fits in range")
}
//---------
if (-1 !in 0..list.lastIndex || list.size !in list.indices) {
println(" out of range")
}
//-----
for (x in 1..10 step 2) {
print(x)
}
println()
for (x in 9 downTo -5 step 3) {
print(x)
}
//13579
//9630-3
//--------
for (i in 1 until 10) { ... } //123456789
for (i in 1.rangeTo(10) step 2) print(i) //13579
(3) if
val result = if (param == 1) {"one"} else if (param == 2) { "two"} else { "three"}
- 集合collection
(1) list
蛮多的,这里不在一一列举,在后续详细讲解
val food = listOf("orange", "apple", "bear", "tomato")//这种方式只读
food
.filter { it.startsWith("a") }
.sortedBy { it.length }
.map { it.toUpperCase() }
.forEach { println(it) }
//APPLE
//AVOCADO
(2) map
val map = mapOf("a" to 1, "b" to 3.4, "c" to "sdf")//这种方式只读
for ((k, v) in map) {
println("$k->$v")
}
- 数组arrays
var array = arrayOf(1, 2, 3)
array[0]=array[1]+array[2]
var array2= doubleArrayOf(1.2,2.3,3.4)
var array3=Array(5,{i->(i*i).toString()}) //["0", "1", "4", "9", "16"]
-
字符串String
- 原生字符串(raw string)由三重引号表示( """ ), 其内容不转义, 可以包含换行符和任意字符
val text = """
for(c in "foo")
print(c)
"""
println(text)
val text = """
|for(c in "foo")
|print(c)
""".trimMargin("|")
println(text)
- 字符串读取内容
(1) s.[0]相当于Java中的s.charAt(0)
(2) for(c in str) 可以读取每个字符
(3) lazy-延迟计算
val p: String by lazy {
// compute the string
}
- 位运算
名称 | Kotlin | Java |
---|---|---|
与 | and | & |
或 | or | || |
异或 | xor | ^ |
有符号左位移 | shl | << |
有符号右位移 | shr | >> |
无符号右位移 | ushr | >>> |
val x = (1 shl 2) and 0x000FF000
- 相等操作符
Kotlin | Java |
---|---|
== | equals |
!= | !equals |
=== | == |
!== | != |
四、导入import
import 关键字不仅可以用来导入类; 还可以用来导入其他声明:
- 顶级(top-level) 函数和属性;
- 对象声明 中定义的函数和属性;
- 枚举常数
那么什么是顶级函数呢?
package demo
val name="a"//顶级属性
fun top(){} //顶级函数
class Teacher
导入:
import demo.name as teacherName//可以使用新名称teacherName访问name
import demo.top
函数, 属性, 类, 对象, 接口, 都可以声明为”顶级的(top-level)”, 也就是说, 直接声明在包之内
五、修饰符
- private 表示只在这个类(以及它的所有成员)之内可以访问;
- protected — 与 private 一样, 另外在子类中也可以访问;
- internal — 在 本模块之内, 凡是能够访问到这个类的地方, 同时也能访问到这个类的 internal 成员;
- public — 凡是能够访问到这个类的地方, 同时也能访问这个类的 public 成员.
open class Outer {
private val a = 1
protected val b = 2
internal val c = 3
val d = 4 // 默认为 public
protected class Nested {
public val e: Int = 5
}
}
class Subclass : Outer() {
// a 不可访问
// b, c 和 d 可以访问
// Nested 和 e 可以访问
}
class Unrelated(o: Outer) {
// o.a, o.b 不可访问
// o.c 和 o.d 可以访问(属于同一模块)
// Outer.Nested 不可访问, Nested::e 也不可访问
}
在 Kotlin 中, 外部类(outer class)不能访问其内部类(inner class)的 private 成员
后记
- 有人在操作过程中,可能会看到添加!!的提示
val c: Int? = null
println(c!!.toString())
这样写会崩溃KotlinNullPointerException, 因为!! 强制编译器执行null类型时跳过null的检查。
- 模块:一个模块(module)是指一起编译的一组 Kotlin 源代码文件:
- 一个 IntelliJ IDEA 模块;
- 一个 Maven 工程, 或 Gradle 工程;
- 通过 Ant 任务的一次调用编译的一组文件