Kotlin
package com.example.test02
import kotlin.math.max
fun main(args: Array<String>) {
val a = 10 // 常量Int
var aa = 10L // 变量Long
var b = "string" // 变量string
// if 语句有返回值
b = if (a > 5) {
println(">")
">"
} else {
println("<")
"<"
}
b = when(a) {
1 -> "1"
2 -> {
print("")
"2"
}
else -> "3"
}
b = when {
a > 0 -> "1"
a > 10 && a % 2==0 -> "2"
else -> "3"
}
// 循环 while 和java中相同
var range = 0..10 // IntRange 变量
for (i in 1..10) {
println(i)
}
for (i in 1 until 10 step 2) { // 左闭右开区间,每次递增2
println(i)
}
// for (i in 10 downTo 1 step 2) [10, 1]每次递增2
println("Hello")
}
// 可使用默认参数,使用时可省略靠后的参数,也可指定传参
fun function(param1:Int = 0, param2: String = " ") {
return
}
fun getMax(num1: Int, num2:Int) : Int = max(num1, num2)
fun getMax2(num1: Int, num2: Int) = if (num1 > num2) num1 else num2
fun checkNumber(num: Number) {
when (num) {
is Int -> println("Int")
is Double -> {
println("Double")
}
else -> println("else")
}
}
/************************** 面向对象(注意,类似java,每个类一个文件) *****************************/
/*
* Kotlin 中有 主构造函数 和 次构造函数
* + 主构造函数
* 类名后的圆括号,其中的字段名用于赋值。默认为空
* 在创建下方Student时必须传入参数 `val stu = Student("a123", 5)`
* 继承时必须通过 () 指定调用的构造方法
* + 次构造函数
* 类内部的 init 代码块
* 当一个类既有主构造函数又有次构造函数时,所有的次构造函数都必须调用主构造函数(包括间接调用)
*/
open class Clazz {
var param1 = ""
var param2 = 0
fun info() {
println("$param1 $param2")
}
}
// 加上open后这个类才可以基础,默认不可以
open class Person(val name: String, val age: Int) {
fun info() {
println(name + " is " + age + "years old.")
}
}
// Student 不可以被继承
// 构造时传入父类参数,再用于构造父类
// 主构造中传给父类的参数不能使用 var val,使用了就是自己的,不能传给父类
// 3种构造方法:
// val stu1 = Student()
// val stu2 = Student("123", 10)
// val stu3 = Student("123", 1, "123", 19)
class Student(val sno:String, val grade: Int, name: String, age: Int) : Person(name, age), Study {
// 主构造函数的的函数体
init {
println("this is init function.")
}
// 次构造函数,必须调用主构造函数
constructor(name: String, age: Int) : this("", 0, name, age) {
}
constructor() : this("", 0) {
}
override fun readBooks() {
}
}
// 只有次构造函数,没有主构造函数
class Student2 : Person {
constructor(name: String, age: Int) : super(name, age) {}
}
// 接口与java种几乎相同,类实现时使用 : 和继承一样
interface Study {
fun readBooks()
fun doHomework() {
println("接口的默认实现")
}
}
// 可见性修饰符有4种:public(默认)、private(当前类可见)、protected(当前类、子类可见)、internal(只对同一模块可见)
// 数据类,自动实现 equals() hashcode() toString() 等方法
data class Cellphone(val brand: String, val price: Double)
// 单例类
object Singleton {
fun singletonTest() {
println("singletonTest is called.")
}
}
/****************************** Lambda ********************************/
// {参数名1: 参数类型, 参数名2: 参数类型 -> 函数体}
fun f() {
val list = ArrayList<String>()
list.add("Apple")
list.add("Banana")
list.add("Orange")
val list2 = listOf("Apple", "Banana", "Orange", "Pear", "Grape")
val list3 = mutableListOf("Apple", "Banana", "Orange", "Pear", "Grape")
val set = setOf("Apple", "Banana", "Orange", "Pear", "Grape")
val map1 = HashMap<String, Int>()
map1["Apple"] = 1
map1["Banana"] = 2
map1["Orange"] = 3
map1["Pear"] = 4
map1["Grape"] = 5
val map2 = mapOf("Apple" to 1, "Banana" to 2, "Orange" to 3, "Pear" to 4, "Grape" to 5)
for ((fruit, number) in map2) {
println("fruit is $fruit, number is $number")
}
val maxLengthFruit1 = list.maxBy({ fruit: String -> fruit.length })
val maxLengthFruit2 = list.maxBy() { fruit: String -> fruit.length }
val maxLengthFruit3 = list.maxBy { fruit: String -> fruit.length }
val maxLengthFruit4 = list.maxBy { it.length }
val newList5 = list.map { it.uppercase() }
val newList6 = list.filter { it.length <= 5 }.map { it.uppercase() }
val anyResult : Boolean = list.any { it.length <= 5 } // 是否有长度大于5的
val allResult : Boolean = list.all { it.length <= 5 } // 是否全部长度大于5
}
/*************************** 空指针 **************************/
// 可以直接用 == 比较类和string,不需要equal方法
// 利用编译时判空检查的机制几乎杜绝了空指针异常
// 空指针异常的检查提前到了编译时期,如果我们的程序存在空指针异常的风险,那么在编译的时候会直接报错,
// 修正之后才能成功运行,这样就可以保证程序在运行时期 不会出现空指针异常了。
fun f2() {
doStudy(null) // 报错,无法编译
doStudy2(null) // 正确
}
fun doStudy(study: Study) { // 此时无法传入 null
study.readBooks()
study.doHomework()
}
fun doStudy2(study: Study?) {
if (study != null) {
study.doHomework()
study.readBooks()
}
study?.readBooks() // 省略了 if-null 判断
var c = study ?: " " // val c = if (study != null) {study} else {" "}
}
fun getTextLength(text: String) = text?.length ?: 0
/****************************** 标准函数 let with run apply*********************************/
/*
let 主要配合 ?. 使用
obj.let { obj2 ->
// 编写具体的业务逻辑
}
obj 作为lambda的参数传入
*/
fun doStudy3(study: Study?) {
study?.let {
it.readBooks()
it.doHomework()
}
}
/*
val result = with(obj : 任意类型) { // lambda表达式
// 这里是obj的上下文
"value" // with函数的返回值
}
*/
val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape")
val result = with(StringBuilder()) {
// 整个Lambda表达式的上下文就会是这个StringBuilder对象
append("Start eating fruits.\n")
for (fruit in list) {
append(fruit).append("\n")
}
append("Ate all fruits.")
toString()
}
println(result)
/*
与with类似
val result = obj.run {
// 这里是obj的上下文
"value" // run函数的返回值
}
*/
val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape")
val result = StringBuilder().run {
append("Start eating fruits.\n")
for (fruit in list) {
append(fruit).append("\n")
}
append("Ate all fruits.")
toString()
}
println(result)
/*
与run类似apply函数无法指定返回值,而是会自动返回调用对象本身
val result = obj.apply {
// 这里是obj的上下文
}
// result == obj
*/
val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape")
val result = StringBuilder().apply {
append("Start eating fruits.\n")
for (fruit in list) {
append(fruit).append("\n")
}
append("Ate all fruits.")
}
println(result.toString())
/******************************* 定义静态方法 ****************************/
/*
1. @JvmStatic 注解
2. 顶层方法:那些没有定义在任何类中的方法,比如 main() 方法。
顶层方法在kotlin中直接调用即可,无需包名、路径
java调用时要使用 文件名.顶层方法() 调用,编译器自动生成一个与文件名同名的类
*/
class Util {
fun doAction1() {
println("do action1")
}
companion object {
@JvmStatic // 只能加在单例类或companion object中的方法上
fun doAction2() {
println("do action2")
}
}
}
// Util.doAction2() 调用
延迟初始化
class MainActivity : AppCompatActivity(), View.OnClickListener {
private lateinit var adapter: MsgAdapter // lateinit 延迟初始化:声明时不用赋值null,使用前赋值即可
override fun onCreate(savedInstanceState: Bundle?) {
...
if (!::adapter.isInitialized) { // ::adapter.isInitialized 返回是否已经初始化
adapter = MsgAdapter(msgList)
}
...
}
}
密封类
fun getResultMsg(result: Result) = when (result) {
is Success -> result.msg
is Failure -> "Error is ${result.error.message}"
// 如果使用 interface 定义Result,这里不得不再加一个else语句
// 密封类及其所有子类只能定义在同一个文件的顶层位置,不能嵌套在其他类中,这是被密封类底层的实现机制所限制的。
}
拓展函数
在不修改源码的情况下给类添加方法:
fun ClassName.methodName(param1: Int, param2: Int): Int {
return 0
}
// 给 String 多添加了一个方法
fun String.lettersCount(): Int {
var count = 0
for (char in this) {
if (char.isLetter()) {
count++
}
}
return count
}
操作符重置
class Obj {
operator fun plus(obj: Obj): Obj {
// 处理相加的逻辑
}
}
class Money(val value: Int) {
operator fun plus(money: Money): Money {
val sum = value + money.value
return Money(sum)
}
operator fun plus(newValue: Int): Money {
val sum = value + newValue
return Money(sum)
}
}
高阶函数
如果一个函数接收另一个函数作为参数,或者返回值的类型是另一个函数,那么该函数就称为高阶函数
fun num1AndNum2(num1: Int, num2: Int, operation: (Int, Int) -> Int): Int {
val result = operation(num1, num2)
return result
}
fun plus(num1: Int, num2: Int): Int {
return num1 + num2
}
fun main() {
val num1 = 100
val num2 = 80
val result1 = num1AndNum2(num1, num2, ::plus)
val result2 = num1AndNum2(num1, num2) { n1, n2 ->
n1 - n2
}
println("result1 is $result1")
println("result2 is $result2")
}
对应的java代码如下:
public static int num1AndNum2(int num1, int num2, Function operation) {
int result = (int) operation.invoke(num1, num2);
return result;
}
public static void main() {
int num1 = 100;
int num2 = 80;
int result = num1AndNum2(num1, num2, new Function() {
@Override
public Integer invoke(Integer n1, Integer n2) {
return n1 + n2;
}
});
}
内联函数
使用lambda都会创建一个匿名类,带来性能开销。使用内联减小开销,在编译时将字节码放到必要的地方。使用 inline
关键字即可。
inline fun num1AndNum2(num1: Int, num2: Int, operation: (Int, Int) -> Int): Int {
val result = operation(num1, num2)
return result
}
noinline与crossinline
// 只内联block1,不内联block2
inline fun inlineTest(block1: () -> Unit, noinline block2: () -> Unit) {
}
内联函数所引用的Lambda表达式中是可以使用return关键字来进行函数返回的,而非内联函数只能进行局部返回。
保证在内联函数的Lambda表达式中一定不会使用return关键字
委托
/**
* 类委托,MySet 的函数实现全部委托由辅助对象实现
*/
class MySet<T>(val helperSet: HashSet<T>) : Set<T> {
override val size: Int
get() = helperSet.size
override fun contains(element: T) = helperSet.contains(element)
override fun containsAll(elements: Collection<T>) = helperSet.containsAll(elements)
override fun isEmpty() = helperSet.isEmpty()
override fun iterator() = helperSet.iterator()
}
// 类委托的简写方式,等于上面
class MySet<T>(val helperSet: HashSet<T>) : Set<T> by helperSet {
fun helloWorld() = println("Hello World")
override fun isEmpty() = false // 可只单独重写某个方法
}
/**
* 属性 p 由 Delegate 对象委托实现,
* 调用p属性的时候会自动调用Delegate类的getValue()方法,
* 当给p属性赋值的时候会自动调用Delegate类的setValue()方法
*/
class MyClass {
var p by Delegate()
}
class Delegate {
var propValue: Any? = null
// 必须用 operator 声明
operator fun getValue(myClass: MyClass, prop: KProperty<*>): Any? {
return propValue
}
operator fun setValue(myClass: MyClass, prop: KProperty<*>, value: Any?) {
propValue = value
}
}
infix
A to B
等价于 A.to(B)
if ("Hello Kotlin".startsWith("Hello")) {
}
// 上面通过 infix 可简写,没有infix这就是一个String类的拓展函数
infix fun String.beginsWith(prefix: String) = startsWith(prefix)
if ("Hello Kotlin" beginsWith "Hello") {
}
if (list.contains("Banana")) {
}
// 等价于
infix fun <T> Collection<T>.has(element: T) = contains(element)
if (list has "Banana") {
}