数据类型
Number
Char
不能隐式转换
String
== 和 ===
字符串模板
$变量
${表达式}
转义字符
rawString
类和对象
定义一个类
class Man constructor( name: String, age: Int) {
init {//方法体
println("My name is $name, and My age is $age")
}
}
复制代码
如果只有一个构造方法,constructor可以省略
class Man ( name: String, age: Int) {
init {
println("My name is $name, and My age is $age")
}
复制代码
如果没有方法,可以省略括号
class Man constructor( name: String, age: Int)
复制代码
new 一个对象,注意不需要new关键字
val man = Man("mr wang", 100)
复制代码
更多构造方法: Kotlin学习系列之:Kotlin的构造函数
继承
//父类
open class Person(color: String) {
init {
println("My color is $color")
println("${this.javaClass.simpleName}")//打印对象的类名
}
}
//子类
class Man(name: String, age: Int, color: String) : Person(color) {//子类的color传递给父类
init {
println("My name is $name, and My age is $age")
}
}
val man = Man("mr wang", 100, "yellow")
println(man is Person)//类似java instanceof
复制代码
My color is yellow Man My name is mr wang, and My age is 100
true
空安全
String?可为空类型,后面.方法,需要先判断空,或者 加?再去.方法
String 不可空类型
fun say(): String? {
return null
}
复制代码
// say()是可null类型,不可以直接.length,处理方式如下:
// println(say().length)//会报错
复制代码
// 方式一:加?
// 如果 say()为null 则打印null,不然就打印length
println(say()?.length)
// 如果 say()为null 则打印"---",不然就打印length,第二个?:表示当你为null是要输出的内容
println(say()?.length ?: "---")
复制代码
// 方式二:!!
// 通知编译器我确定不会是null
println(say()!!.length )
复制代码
智能类型转换
如果知道p是child不需要强转
// java
Parent p = new Child();
if (p instanceof Child) {
((Child) p).hello_in_child();
}
复制代码
//kotlin
val parent: Parent = Child()
if( parent is Child){
// hello_in_child是child的方法,因为判断了parent is Child ,所以不需要强转
parent.hello_in_child()
}
复制代码
强转写法 as
val p = Parent()
val child: Child = p as Child
这样写会报错,因为明显p的类型是父类Parent ,p是不能转为子类的
复制代码
java.lang.ClassCastException: com.kotlin.www.kotlindemo.Parent cannot be cast to com.kotlin.www.kotlindemo.Child
at com.kotlin.www.kotlindemo.ExampleUnitTest.addition_isCorrect(ExampleUnitTest.kt:46) 复制代码
解决方法:as?
可以强转就强转,不能的话就返回null
val p = Parent()
val child: Child? = p as? Child
println(child)
复制代码
null
包
// 虽然位于不同包名下,但是这样会报错,提示冲突
import com.kotlin.www.kotlindemo.test.Parent
import com.kotlin.www.kotlindemo.Parent
复制代码
//要加入as起个别名区分,以后用这个类也必须使用别名
import com.kotlin.www.kotlindemo.test.Parent as TestParent
import com.kotlin.www.kotlindemo.Parent as Parent
val p1=TestParent()
val p2=Parent1()
复制代码
区间
val range=1..3 //[1,3]
val range1=1 until 3//[1,3)
复制代码
遍历
for (r in range){
println(r)
}
复制代码
判断在不在区间内 in 操作符 或者 contains
println(3 in range)
println(3 in range1)
println(range.contains(3))
println(range1.contains(3))
复制代码
true false true false
数组
i
基本类型内置数组类型
val byteArray = byteArrayOf(1, 2, 3)
val charArray = charArrayOf('a', 'b', 'c')
val intArray: IntArray = intArrayOf(1, 2, 3, 4, 5, 6, 7, 8, 9)
val floatArray: FloatArray = floatArrayOf(0.1f, 0.2f, 0.3f)
val booleanArray = booleanArrayOf(true, true, true)
val shortArray = shortArrayOf(1, 2, 3)
val longArray = longArrayOf(1, 2, 3)
val doubleArray = doubleArrayOf(0.1, 0.2, 0.3)
通用定义方式为:
val array: Array<Parent1> = arrayOf(Parent1(), Parent1(), Parent1())
val array1: Array<String> = arrayOf("hello","nihao","dajiahao")
val arrayOf:Array<Int> = arrayOf(1, 2, 3)
复制代码
val intArray: IntArray = intArrayOf(1, 2, 3, 4, 5, 6, 7, 8, 9)
// 切片
val slice = intArray.slice(1..3)
复制代码
[2, 3, 4]
程序结构
val
val定义的不可变,基本类似于java的final,要想完全一样,要加上const
函数
一般函数
fun say(): String? {
return "djh"i
}
// 一般函数
fun sum(a: Int, b: Int) = print(a + b)
sum(1, 2)
复制代码
匿名函数
// 匿名函数
val sum1 = fun(a: Int, b: Int) = print(a + b)
sum1(1, 2)
复制代码
lambda表达式
写法
// lamda表达式
val sum2 = { a: Int, b: Int ->
println("$a+$b=${a + b}")
a + b
}
复制代码
lambda表达式作为参数传递
val arrayInt = intArrayOf(1, 2, 3, 4, 5, 6, 7, 8, 9)
// 接收一个lambda表达式 ( (Int) -> Unit )
arrayInt.forEach({ it: Int -> println(it) })
// 只有一个参数时候,it可以省略
arrayInt.forEach { println(it) }
// 还可以更省略
arrayInt.forEach(::println)
复制代码
注意事项,lambda表达式return会return整个函数
private fun xunhuan() {
val arrayInt = intArrayOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
arrayInt.forEach {
if (it == 3) {
return//因为lambda是表达式,这里return 会让整个xunhuan函数返回,最后的一句话不会打印
}
println(it)
}
println("dajiahao")
}
复制代码
如何解决问题呢
private fun xunhuan() {
val arrayInt = intArrayOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
arrayInt.forEach forEach@{
if (it == 3) {
return@forEach//这样写,最后的一句话会打印
}
println(it)
}
println("dajiahao")
}
复制代码
lambda表达式是有类型的
lambda表达式的简化使用方法
类
定义属性
构造方法写在类名字后面
属性访问控制 get set
java的get set 方法
想写kotlin的get set方法怎么办 ,默认有的get set
属性初始化
运算符
class Student(var age: Int) {
// 运算符"+"相当于plus函数,注意必须是plus名称的函数才对应+,参数个数必须是一个,其他没要求
operator fun plus(s: Student): Student {
return Student(age + s.age)
}
}
val s1 = Student(1)
val s2 = Student(2)
val s3 = s1 + s2
// val s3 = s1.plus(s2)//等同于上面
print(s3.age)//输出3
复制代码
中缀表达式
class Student(var age: Int) {
infix fun on(i: Any):Boolean {
return true
}
}
复制代码
s1.on(1)
s1 on 1//上面的式子可以简写成 s1 on 1,中缀表达式多用于dsl,一般不用,因为表达不是太清楚
复制代码
分支表达式
if 表达式
when表达式 替代switch
when也可以是表达式,也就是可以把他赋值给变量,每个分支最后一个值就是返回值
循环
异常
异常写法
异常表达式
具名参数
变长参数
test(1,2,3,4,5,6,7,8,9,s="fds")
fun test(vararg ints:Int,s:String):Int{
println(ints[0])
return ints[0]
}
复制代码
展开操作符*
val arr = intArrayOf(1, 2, 3)
test(*arr, s = "fff")
复制代码
默认参数
val arr = intArrayOf(1, 2, 3)
test(ints = *arr, s = "fff")//由于使用了默认参数double(没传递),第一个参数会有歧义,这时候需要指定具名参数
fun test(double: Double = 1.0, vararg ints: Int, s: String): Int {
println(ints[0])
return ints[0]
}
复制代码
面向对象
继承
![image-20190414194650600](/Users/apple/Library/Application Support/typora-user-images/image-20190414194650600.png)
一个类必须open才能被继承
abstract抽象类和interface接口默认含有open,所以可以直接被继承
父类方法属性也必须open才能被复写,复写必须写override关键字
接口代理
package com.kotlin.www.kotlindemo.daimazai
interface Writer {
fun write()
}
interface Driver {
fun drive()
}
class MyWriter : Writer {
override fun write() {
println(" I can write")
}
}
class MyDriver : Driver {
override fun drive() {
println("I can drive")
}
}
//一般接口实现的写法
class Manager : Writer, Driver {
override fun drive() {
println("I can Drive")
}
override fun write() {
println("I can write")
}
}
//接口代理的写法(不要事必躬亲),不需要再次重写接口里的实现方法,而是通过构造函数传递进来一个已经实现接口的实现类对象直接使用这个对象的方法就行
class SeniorManager(private val writer: MyWriter, private val driver: MyDriver) : Writer by writer, Driver by driver
fun test_() {
// 接口代理写法
val myWriter = MyWriter()
val myDriver = MyDriver()
val seniorManager = SeniorManager(myWriter, myDriver)
seniorManager.write()
seniorManager.drive()
// 普通实现接口
val manager = Manager()
manager.drive()
manager.write()
}
复制代码
接口方法冲突
package com.kotlin.www.kotlindemo.daimazai
abstract class A {
open fun hello(): Int = 1
}
interface B {
fun hello(): Int = 2
}
interface C {
fun hello(): Int = 3
}
class D(var y: Int) : A(), B, C {
override fun hello(): Int {
if (y > 100) {
return super<A>.hello()//注意使用泛型指明是哪一个接口(抽象类)的方法
} else if (y > 10) {
return super<B>.hello()
} else {
return super<C>.hello()
}
}
}
fun test___(){
val d = D(1000)
val hello = d.hello()
println(hello)
}
复制代码
接口
接口可以有实现方法
可见性
object kotlin的单例写法
java调用object单例
伴生对象与静态成员
定义
java调用
在定义时候加上注解
java调用更加方便
定义了一个静态成员
java使用kotlin的静态成员
方法重载
下面一个默认参数
java如何调用kotlin的默认参数函数呢 必须先改造kotlin写法
扩展成员(方法和属性)
注意:扩展方法定义在了一个Extend.kotlin文件里,不是被扩展的类String里,所以java里如何使用呢
本质是
扩展成员属性
属性代理
属性代理目的
为了让使用属性时候能做更多操作
例如file getfile读文件 setfile 写文件
外界通过访问属性,完成了很多事情
经典例子就是lazy
写代理就是实现getValue和setValue方法,看着下面的class X写就ok
lazy解析
val 只要实现get
var 实现 get set
数据类
加上data,kotlin默认干了很多事情
自己写component
dataclass当做Javabean使用的坑
如何解决呢 使用两个注解
-
先 引入依赖
-
自定义注解
结果
但是这是在编译期时,操作字节码实现的,所以虽然有无参构造方法,你的代码是在编译期前面写的,此时还没有无参构造方法,但是反射可以拿到
内部类
kotlin默认内部类写法是静态内部类
inner 关键字 实现非静态内部类
匿名内部类
枚举
实例可数
密封类
子类可数
高阶函数
map 几何元素转换
val list = listOf(1, 2, 3, 4)
println(list)//[1, 2, 3, 4]
val list1 = list.map { it * 2 + 3 }//[1, 2, 3, 4]
val list2 = list.map { it.toDouble() }//[1.0, 2.0, 3.0, 4.0]
val list3 = list.map(Int::toDouble)//[1.0, 2.0, 3.0, 4.0]
复制代码
flatmap 集合打平
//集合的集合
val list = listOf(
1..10,
10..13,
30..37
)//[1..10, 10..13, 30..37]
//打平
val list1 = list.flatMap { it + 100 }
//[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 100, 10, 11, 12, 13, 100, 30, 31, 32, 33, 34, 35, 36, 37, 100]
//所有数字前加No. 注意不同it代表含义不同
val list2 = list.flatMap {
it.map {
"No.$it"
}
}
// [No.1, No.2, No.3, No.4, No.5, No.6, No.7, No.8, No.9, No.10, No.10, No.11, No.12, No.13, No.30, No.31, No.32, No.33, No.34, No.35, No.36, No.37]
复制代码
reduce 累计操作
val list = listOf(1, 2, 3, 4)
val reduce = list.reduce { acc, i -> acc + i }//累加 10
val reduce1 = list.reduce { acc, i -> acc * i }//累乘法 24
//拼接字符串
val list = listOf("java", "kotlin", "c++")
val ccc= list.reduce { acc, s -> acc+","+s }
println(ccc)//java,kotlin,c++
复制代码
/**
* 求阶乘
*/
fun jiecheng(n: Int): Int {
return if (n == 0) {
1
} else {
(1..n).reduce { acc, i -> acc * i }
}
}
// 集合map变为阶乘,再循环打印
(0..9).map(::jiecheng).forEach(::println)
// 集合map变为阶乘,再累加集合里的元素
(0..9).map(::jiecheng).reduce { acc, i -> acc + i }
复制代码
fold 累计运算,但是可以指定初始值
(0..9).reduce { acc, i -> acc+i }//45
(0..9).fold(100) { acc, i -> acc+i }//145 (100)为指定的初始值
val c= (0..9).fold(StringBuilder("qwe")){ acc, i ->acc.append(i).append(",") }
println(c)//qwe0,1,2,3,4,5,6,7,8,9,
复制代码
foldRight 从右往左累计运算(指定初始值 )
val list = listOf("java", "kotlin", "c++")
val w=list.foldRight(StringBuilder()){
s: String, acc: StringBuilder ->
acc.append(s).append(",")
}
//c++,kotlin,java,
复制代码
joinToString 连接字符串
val list = listOf("java", "kotlin", "c++")
val q=list.joinToString(",")//java,kotlin,c++
复制代码
filter 过滤元素
// 返回偶数(模2为0的数字)的元素
val filter = (0..10).filter { it % 2 == 0 }
println(filter)//[0, 2, 4, 6, 8, 10]
复制代码
filterIndexed 过滤索引+元素
//获取奇数位置的数字
val a: IntArray = intArrayOf(9, 8, 7, 3, 7)
val ccc= a.filterIndexed { index, i -> index % 2 == 0 }//[9,7,7]
复制代码
takeWhile 和 takeLastWhile
// 取出数组里的奇数元素,遇到不是奇数就停止
val qwe: IntArray = intArrayOf(17, 9, 8, 19, 3, 7)
val ok = qwe.takeWhile { it % 2 == 1 }// [17, 9] 从前往后取
val last = qwe.takeLastWhile {it % 2 == 1 }//[19, 3, 7] 从后往前取值
复制代码
let
data class Cat constructor(var name: String, var age: Int)
fun main() {
println(100)
// 因为 findCat()?已经非空判断了,所以后面可以直接使用
findCat()?.let {
print(it.name)
print(it.age)
}
// 使用了dataclass的解包操作 component1,2
findCat()?.let { (name, age) ->
{
print(name)
print(age)
}
}
}
fun findCat(): Cat? {
return null
}
复制代码
apply
package objectori
data class Cat constructor(var name: String, var age: Int) {
fun work() {
}
fun play() {
}
}
fun main() {
println(100)
// 因为 findCat()?已经非空判断了,所以后面可以直接使用
findCat()?.let {
print(it.name)
print(it.age)
it.play()//在let里可以直接用it调用方法
}
findCat()?.apply {
// 在apply里可以直接调用方法,
work()
play()
name
age
}
/
}
fun findCat(): Cat? {
return null
}
复制代码
use with
略
尾递归优化
函数调用了自己后没有任何操作 关键是分辨什么是尾递归
闭包
对象携带状态
fun makeFun(): ()->Unit{
var count =0
// 返回一个函数
return fun(){
count++
println(count)
}
}
fun main() {
var x= makeFun()
x()
x()
x()
x()
}
//1
2
3
4
复制代码
package objectori
/**
* start;起始步数
* step:每次走的步数
*
*/
fun makeFun(start: Int, step: Int): () -> Unit {
var count = start
// 返回一个函数
return fun() {
count += step
println(count)
}
}
fun main() {
var x = makeFun(100,2)
x()
x()
x()
x()
}
102
104
106
108
复制代码
函数的复合
下面是两个函数
add5:把一个值加5
multiplyBy2:把一个值乘以2
fun main() {
val add = add5(8)
val multi = multiplyBy2(add)
println(add) //13
println(multi)//26
}
//加5
val add5 = { i: Int -> i + 5 }
//乘2
val multiplyBy2 = { i: Int -> i * 2 }
复制代码
fun main() {
val add = add5(8)
val multi = multiplyBy2(add)
println(add) //13
println(multi)//26
// val result = add5.andThen(multiplyBy2)
val result = add5 andThen multiplyBy2
println(result(8))
}
//加5
val add5 = { i: Int -> i + 5 }
//乘2
val multiplyBy2 = { i: Int -> i * 2 }
infix fun <P1, P2, R> Function1<P1, P2>.andThen(function: Function1<P2, R>): Function1<P1, R> {
return fun(p1: P1): R {
return function.invoke(this.invoke(p1))
}
}
复制代码
科理化
偏函数
协程
参考这篇文
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
coroutine.setOnClickListener { click() }
}
private fun click() = runBlocking {
GlobalScope.launch(Dispatchers.Main) {
coroutine.text = GlobalScope.async(Dispatchers.IO) {
// 比如进行了网络请求
// 放回了请求后的结构
return@async "main"
}.await()
}
}
}
复制代码
更好的入门 www.kotlincn.net/docs/tutori…
与java交互
SAM转换 单一抽象方法 Single Abstract Method
注意:
示例一 kotlin引用java里的函数(sam转换只是默认支持java接口)
- 在java里定义一个addTask(参数为接口实现)
public class SamJava {
public void addTask(Runnable runnable){
}
}
复制代码
- kotlin调用这个方法
val samJava = SamJava()
samJava.addTask(object : Runnable {
override fun run() {
// do sth
}
})
samJava.addTask {
// do sth
}
复制代码
示例二 kotlin引用kotlin里的函数(sam转换只是默认不支持kotlin接口)
只能这样调用
val samKotlin = SamKotlin()
samKotlin.addTask(object :Runnable{
override fun run() {
}
})
复制代码
如果kotlin接口想使用sam的话
必须加别名
typealias Runnable = () -> Unit
复制代码
完整如下:
typealias Runnable = () -> Unit
class SamKotlin {
fun addTask(runnable: Runnable) {
}
}
fun test() {
val samKotlin = SamKotlin()
samKotlin.addTask {
// do sth
}
}
复制代码
为Runnable起了别名后, java调用加别名后的kotlin 方式如下:
SamKotlin samKotlin=new SamKotlin();
// 为Runnable起了别名后, java调用加别名后的kotlin
samKotlin.addTask(new Function0<Unit>() {
@Override
public Unit invoke() {
return null;
}
});
// 简写如下:
samKotlin.addTask(() -> null);
}
复制代码
正则表达式
java写法
kotlin写法
直接抄java
也可以用有kotlin自己的写法
集合框架
mapOf同理不可变
注意
java认为kotlin listOf定义的list与普通list没区别,支持调用add remove ,但是实际运行会报错
先在kotlin使用listOf定义一个list
IO 操作
Java里面
自带关闭流
简单文件读写
File("KotlinDemo.iml").readLines().forEach(::println)
复制代码