序号 | 类型 | 位宽 | 最小值 | 最大值 |
---|---|---|---|---|
1 | Byte | 8 | -128 | 127 |
2 | Short | 16 | -32768 | 32767 |
3 | Int | 32 | -2,147,483,648 (-2^31) | 2,147,483,647 (2^31 - 1) |
4 | Long | 64 | -9,223,372,036,854,775,808 (-2^63) | 9,223,372,036,854,775,807 (2^63 - 1) |
val number = 100 //默认Int类型 类比java的Integer
val bigNumber = 80000000000 //超过Int类型默认Long
val longNUmber = 20L //手动添加L 标明Long类型
val byteNumber: Byte = 1 //晟敏层Byte类型
// 类似于Java中的public static void main(String[] args){}
// kotlin中存在两种main方法的写法,都可以
// var相当于是一个变量 val对比java中相当于是final修饰的变量,不允许修改
fun main(){
var intNum = 100
}
fun main(args: Array<String>){
val num = 100
}
序号 | 类型 | 位宽 | 小数精度 |
---|---|---|---|
1 | Float | 32 | 6位 |
2 | Double | 64 | 15-16位 |
Kotlin 对于小数的默认推断是
Double
类型。如果需要显式将一个小数指定为Float
类型需要在数值尾部加入f
或F
。由于Float
类型十进制位数是6位
,所以例子中floatNumber
实际值大小为3.1415926
,后面就会出现进度丢失舍弃。在 Kotlin 中还有一点与 Java 不同的是,Kotlin 中数字不存在隐式的拓宽转换。比如一个函数参数为
Double
的函数只能接收Double
类型,不能接收Float
、Int
或者其他数字类型
val doubleNumber = 3.1415928888 //默认是Double类型
val floatNumber = 3.1415928888f //尾部加f或F显式表示这是一个Float类型的浮点数
在Kotlin中,字符类型用
Char
表示
fun testChar(char: Char){
if(char == '4'){
//TODO
}
}
在 Kotlin 使用
Boolean
表示布尔类型,它只有两个值true
和false
。注意可空类型Boolean?
类型会存在装箱操作。
var isVisible: Boolean = false
val isVisible = false //自动推断为布尔Boolean类型
在 Kotlin 中字符串用
String
类型表示。字符串是不可变的。 字符串的元素——字符可以使用索引运算符访问:s[i]
。 可以用 for 循环迭代字符串:
val str="1234567890"
for(char in str) {
println(char)
}
使用
"""
创建模板字符串
var stringTemplate = """
创建模板字符串
"""
stringTemplate = stringTemplate.trimMargin()
$
替换模板中的内容fun main(){
showAge(17)
}
fun showAge(age: Int){
// 如果传过来是一个对象的话需要加 {} 在里边调用属性
println("输入的年龄是 ${age}")
println("输入的年龄是 $age")
// 可以用来代替java中的写法
println("输入的年龄是" + age)
}
通过toByte等函数转换
序号 | 类型 | 强转函数 |
---|---|---|
1 | Byte | toByte() |
2 | Short | toShort() |
3 | Int | toInt() |
4 | Long | toLong() |
5 | Float | toFloat() |
6 | Double | toDouble() |
7 | Char | toChar() |
val number = 100
number.toString()
number.toByte()
...
Kotlin 中的位运算和 Java 不同的是没有用特殊符号来表示,可以采用了中缀函数方式调用具名函数。
shl(bits)
– 有符号左移【shl是Shift Logical Left的缩写】shr(bits)
– 有符号右移ushr(bits)
– 无符号右移and(bits)
– 位与or(bits)
– 位或inv()
– 位非xor(bits)
– 位异或val vip= true
val admin= false
val result = vip and(admin) =false
val result = 8 ushr(2) = 2
容器是用于存放数据的载体。容器分为数组、集合。
Kotlin作为一门全新的语言,肯定还是要有自己的容器类,不然哪天Java跟Kotlin划清界限,那麻烦就大了。
Kotlin也拥有三类基本的容器,分别是集合Set、队列List、映射Map,每种容器又分作只读与可变两种类型这是为了判断该容器能否进行增删改等变更操作。
数组是一种初始化时指定容器大小,不可以动态调整其大小的容器。元素按顺序存储在一串连续的内存段上
创建一份数组并赋值元素,数组内可以是任意元素
val array = arrayOf(1, 2, 3)
val array = arrayOf(1, true, "2", JSONObject()) //
创建一个指定大小的、所有元素都为空的数组,但必须指定集合中的元素类型
var arrayOfNulls = arrayOfNulls<String>(10)
创建出来一个闭合区间 这个与下边的4准确的说应该是是属于Range
var numArr = 1 .. 9 //打印出来 1-9
var charArr = 'a' .. 'z' // 打印出来 a - z
创建出来一个左闭右开的数组 [n,m),
var intRange = 1 until 9 //数组中只有1-8
使用Array的构造函数,动态创建数组
// 这个函数会创建五个元素,分别是 0 1 4 9 16
var intArr = Array(5){i -> (i * i).toString()}
Kotlin中提供了不需要拆装箱的原生类型数组,
Kotlin数组类型不是集合的一种,但是**数组和集合可以互相转换,初始化集合的时候也可以传入一个数组**
序号 | 原生类型数组 | 描述 |
---|---|---|
1 | ByteArray | 字节型数组 |
2 | ShortArray | 短整型数组 |
3 | IntArray | 整型数组 |
4 | LongArray | 长整型数组 |
5 | BooleanArray | 布尔数组 |
6 | CharArray | 字符型数组 |
7 | FloatArray | 浮点型数组 |
8 | DoubleArray | 双精度浮点型数组 |
val array = arrayOf(1,2,3,4,5,6,7,8,9,0)
array[4] //获取下标是4的元素
array.component1() // 获取数组中第一个元素 注意是第一个,不是下标 1
...
array.component5() // 获取数组中第五个元素
//用法与js中的 for in 类似,比较与java的增强for少了一个元素类型
for(item in array){
println(item)
}
for(index in array.indices){
println("下标 $index 的元素是 ${array[index]}")
}
与上一节相比这个可以同时使用index和元素
for((index,item) in array.withIndex()){
println("下标 $index 的元素是 $item")
}
forEach遍历,循环中的元素固定是it
array.forEach{
println(it) //默认就是it ,不需要声明这个变量
}
同时遍历下标和元素
array.forEachIndexed { index,item ->
println("$index ,$item")
}
array.reverse()
Kotlin 标准库提供了一整套用于管理集合的工具,集合是可变数量(可能为零)的一组条目,各种集合对于解决问题都具有重要意义,并且经常用到。与数组不同的是可变集合的大小可以动态改变。
- List: 是一个有序集合,可通过索引(反映元素位置的整数)访问元素。元素可以在 list 中出现多次。列表的一个示例是一句话:有一组字、这些字的顺序很重要并且字可以重复。
- Set: 是唯一元素的集合。它反映了集合(set)的数学抽象:一组无重复的对象。一般来说 set 中元素的顺序并不重要。例如,字母表是字母的集合(set)。
- Map: (或者字典)是一组键值对。键是唯一的,每个键都刚好映射到一个值,值可以重复。
- 虽说List和Set是不可变集合,但是也可以通过
list = list.plus(element)
的方式添加元素后重新给集合赋值
数组创建方式 | 示例 | 说明 | 是否可变 |
---|---|---|---|
arrayListOf() mutableListOf 相同元素类型的队列 | val array = arrayListOf(1, 2, 3) val array = mutableListOf() | 必须指定元素类型 | 可变 |
listOf() 相同元素类型的集合 | val array = listOf(1, 2, 3) | -必须指定元素类型 - 必须指定初始化数据元素 | 不可变 |
arrayMapOf |
val array= arrayMapOf(Pair(“key”,“value”)) val array= mutableMapOf() | 初始元素使用Pair包装 | 可变 |
mapOf() 相同元素类型的字典 | val array= mapOf(Pair(“key”,“value”)) var map = mapOf(“key” to “value”) |
元素使用Pair包装 必须指定初始元素 | 不可变 |
arraySetOf() mutableSetOf 相同元素类型的集合 | val array= arraySetOf(1,2,3) val array= mutableSetOf() | - 会对元素自动去重 | 可变 |
setOf() 相同元素类型的集合 | val array= arraySetOf(1,2,3) | - 对元素自动去重 - 必须指定元素类型。 | 不可变 |
与java一样Set是无序排列的
只读集合,一般来说初始化之后不可更改,但是也可以通过plus或者是plusElement更改元素
var set = setOf<String>("123","456")
set = set.plus("0")
println(set) //打印123 456 0
创建的可变集合,但是对集合内元素操作也有限制,与Java中的Set操作方法类似
add方法只能添加元素,但是因为Set是无序的,所以不知道元素添加的位置
没有修改元素值的方法,应该可以通过iterator进行remove和add操作来实现
remove方法只能删除指定的元素,不能通过下标删除
对于循环操作,提供了for-in 、迭代器、forEach等
for-in
var phoneSet = mutableSetOf<String>("小米", "红米", "oppo")
// 类似js中的forin或者是java中的增强for
for(phone in phoneSet){
println(phone)
}
//并不能像 java那样 ,下班这个在kotlin中是不可用的
// for(Iterator iterator = phoneSet.iterator();iterator.hasNext();){}
var iterator = phoneSet.iterator()
while(iterator.hasNext()){
println(iterator.next())
}
在foreach中固定使用it代替循环中的每一个元素,不能替换成其他的变量
// 在forEach中使用 it代替,固定的it不能修改成其他的变量
phoneSet.forEach{ println("$it")}
也是分为List和MutableList,List不可修改(也可以通过 list = list.plus(“”)修改),MutableList可以
与Set类似,没有add方法,但是可以通过plus plusElement添加元素
var list = listOf<String>("123")
list = list.plus("456")
list = list.plusElement("789")
println(list)
可变的集合,支持增删改查操作,常用的方法有
fun main() {
val strList = listOf("买鸡蛋","买肉","买菜")
for ((index,element) in strList.withIndex()) {
println("$index $element")
}
}
var listOf = mutableListOf<String>("123", "4564", "78944")
// 这种写法和循环一样,每一个元素都是it且是正序排列的
listOf.sortBy { it.length }
println(listOf)
// 这个方法是按照指定规则倒序排列的
listOf.sortByDescending{it.length}
println(listOf)
Map可以按照
java
中的put方法赋值,但是Kotlin
建议用map[“K”] = val
fun main() {
val map = TreeMap<String,String>()
map["A"] = "1"
map["B"] = "2"
map["C"] = "3"
map.put("D","4")
println(map)
}
Map初始化的方法有所不同,一共有两种方式
- A to B
- Pair(A,B)
var mapOf = mapOf("test" to "test", Pair("test1", "test1"))
println(mapOf)
- 方法由关键字
fun
声明- 后边紧跟着方法名称
- 括号里是方法的参数,名称在前 :类型在后
- 最后返回写返回类型
fun addNum(firstNum: Int,lastNum: Int) :Int{
return firstNum + lastNum
}
class Person{
fun eat(){
println("人需要吃饭")
}
}
fun main(){
Person().eat()
}
使用
companion object
实现类似java中的static功能
class Person{
// 不需要创建爱你对象,可以直接使用类名.方法调用
companion object{
fun eat(){
println("吃饭")
}
}
}
fun main(){
Person.eat()
}
使用**关键字 object**声明静态类
object Person(){
fun eat(){
println("人需要吃饭")
}
}
fun main(){
Person.eat()
}
// 当然这里的返回值类型也可以不用写,可以由编译器自动推断类型
fun addNum(a: Int,b: Int) :Int = a + b
fun main(){
val sum = {a: Int,b: Int -> a + b}
println(sum(4, 16))
}
fun main(){
val sum = (Int,Int) -> Int = {x,y -> x + y}
println(sum(4,6))
}
方法参数可以有默认值,当**省略相应的参数是会使用默认值,与java相比可以减少重载方法的数量**
val PI = 3.14f
fun main(){
/**
* 因为这里circumference方法中的Pi参数的值已经知道了是固定的PI
* 所以需要只需要指定radius的值就可以了
* 这里边的Pi就是默认参数,每次都是固定值
* radius 就是具名参数
*/
println(circumference(radius = 2f))
}
fun circumference(Pi:Float = PI,radius:Float) = 2 * Pi * radius
在上一章节中,如果第一个参数使用默认值的话
radius
就是具名参数如果默认参数之后的最后一个参数是lambda表达式,那么他既可以作为具名参数在括号内传入,也可以在括号外传入
// 当方法不需要返回值的时候需要使用 Unit
fun foo(bar: Int = 0,baz: Int = 1, action: () -> String){
val actionString = action()
}
//括号内接收返回值
foo(1,2,action ={
val result = 2
// 在方法体中的最后一句就是返回值,所以不需要写return
"inside String"
})
//括号外传递值,当且仅当最后一个参数是lambda函数的时候才能写在括号外边
foo(){
"括号外传递action参数"
}
相当于是Java中的 … ,在Kotlin中使用**vararg 关键字**
fun append(vararg str: Char) :String{
val result = StringBuffer()
for(char in str){
result.append(char)
}
return result.toString()
}
fun main(){
val appendStr = append('S','t','r','i','n','g')
println(appendStr)
}
可变参的要求
- 只有一个参数可以标注为 vararg;
- 如果 vararg 参数不是列表中的最后一个参数, 可以使用具名参数语法传递其后的参数的值,或者,如果参数具有方法类型,则通过在括号外部传一个 lambda。
当我们调用 vararg 方法时,我们可以一个接一个地传参,例如 append(‘h’, ‘e’, ‘l’, ‘l’, ‘o’),或者,如果我们已经有一个数组并希望将其内容传给该方法,我们使用伸展**(spread)操作符(在数组前面加 *)**:
val world = charArrayOf('w','o','r','l','d')
val result = append('h','e','l','l','o',' ',*world)
kotlin 支持局部方法,即一个方法在另外一个方法内部,局部方法可以方位外部方法中的变量
fun magic(): Int {
fun foo(v: Int): Int {
return v * v
}
val v1 = (0..100).random()
return foo(v1)
}
Lambda表达式的本质其实是匿名方法,因为在其底层实现中还是通过匿名方法来实现的。但是我们在用的时候不必关心起底层实现。不过Lambda的出现确实是减少了代码量的编写,同时也是代码变得更加简洁明了
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(v.getContext(), "Lambda简洁之道", Toast.LENGTH_LONG).show();
}
});
匿名方法,可传递
view.setOnClickListener { v -> Toast.makeText(v.context, "Lambda简洁之道", Toast.LENGTH_LONG).show() }
无参数的情况
var arg = {//TODO}
有参数的情况
val arg : (参数类型,参数类型) -> 返回值类型 = {参数1,参数2 -> 操作代码}
// 等价于下边这种写法:即表达式的返回值类型会根据操作的代码自推导出来。
var 变量名 = { 参数1 : 类型,参数2 : 类型, ... -> 操作参数的代码 }
- it并不是Kotlin中的一个关键字(保留字)
- it是在当一个高阶方法中Lambda表达式的参数只有一个的时候可以使用it来使用此参数
- it可表示为单个参数的隐式名称,是Kotlin语言约定的
var arrayOf = arrayOf("1", 1, 2, false)
arrayOf.forEach { println(it) }
在lambda表达式中不需要使用这个参数的时候,可以使用
_
代替
fun main() {
var mapOf = mapOf<String, Any>("1" to "2", "4" to false)
mapOf.forEach{ (key, value) ->
println("$key : $value")
}
mapOf.forEach{(_,value) ->
println(value)
}
}
kotlin中的if表达式会返回一个值,如果不写return语句的话,会默认返回if表达式作用域的最后一行
fun maxNum(a: Int,b: Int){
if(a > b){
return a
}else{
return b
}
}
因为kotlin中的if-else自带return返回值,所以没有像java中的三目运算符,可以使用下面的例子代替
fun minNum(a :Int,b :Int){
return if(a < b) a else b
}
使用when代替了switch-case语句,如果when表达式需要有返回值的话,则必须要带有else分支
fun judgeScore(score:Int){
when(score){
10 -> println("满分牛逼")
9 -> println("也不错")
8 -> println("还可以")
else -> println("继续努力")
}
}
在Kotlin 1.3版本以后,可以通过其他方法获取when判断的值
fun main(args: Array<String>) {
when (val value = getValue()) {//when表达式条件直接是一个表达式,并用value保存了返回值, 实际上相当于把外部那一行缩进来写
is Int -> "This is Int Type, value is $value".apply(::println)
is String -> "This is String Type, value is $value".apply(::println)
is Double -> "This is Double Type, value is $value".apply(::println)
is Float -> "This is Float Type, value is $value".apply(::println)
else -> "unknown type".apply(::println)
}
}
fun getValue(): Any {
return 100F
}
和
if
表达式一样,when
表达式也是带有返回值的。建议对于多层条件级或嵌套条件控制的使用建议使用when
替代if-else
:
fun eval(number: Number) {
if (number is Int) {
println("this is int number")
} else if (number is Double) {
println("this is double number")
} else if (number is Float) {
println("this is float number")
} else if (number is Long) {
println("this is long number")
} else if (number is Byte) {
println("this is byte number")
} else if (number is Short) {
println("this is Short number")
} else {
throw IllegalArgumentException("invalid argument")
}
}
//多层级条件使用when表达式
fun eval(number: Number): String = when (number) {
is Int -> "this is int number"
is Double -> "this is double number"
is Float -> "ths is float number"
is Long -> "this is long number"
is Byte -> "this is byte number"
is Short -> "this is Short number"
else -> "invalid number"
}
*for 循环* 可以对任何提供迭代器(iterator)的对象进行遍历,for 循环仅以唯一一种形式存在, 和 Java的 for-each 循环一致。其写法
for
和 C# 一样。和 Java 类似,循环最常见的应用就是迭代集合,具体语法如下:- in
类似java中的增强for但是不需要写明类型
var list = listOf<Int>(1,2,3,4,5)
for(item in list){
println("$item")
}
for(index in list.indices){
println("$index")
}
for((index,item) in listOf.withIndex()){
println("下标是 $index 的元素是$item")
}
与java中的一直,不做过多赘述
var arr = 1 .. 10
// 输出 1 2 3 4 5 6 7 8 9 10
arr.forEach { println(it)}
var arr = 1 until 5
// 输出 1 2 3 4
arr.forEach { println(it)}
var arr = 5 downto 1
// 输出 5 4 3 2 1
arr.forEach { println(it)}
var arr = 1 .. 10
// 输出 1 3 5 7 9
for(it in arr step 2){
println(it)
}
泛型种类 | Java 中代码示例 | Kotlin 中代码示例 | 说明 |
---|---|---|---|
泛型类型 | class Box | class Box | 泛型类型 |
泛型方法 | T fromJson(String json, Class tClass) | fun fromJson(json: String, tClass: Class): T? | 泛型函数 |
有界类型参数 | class Boxclass Box |
泛型类型约束 |
|
上界通配符 | void sumOfList(List extends Number> list) | fun sumOfList(list: List) | 泛型上限约束 |
下界通配符 | void addNumbers(List super Integer> list) | fun addNumbers(list: List) | 泛型下限型约束 |
定义反应类型,是在类型名之后,主构造函数之前用尖括号起的大写字母类型参数指定:
interface Drinks<T>{
fun price(t: T)
fun taste(): T
}
abstract class Color<T>(var t: T/*泛型字段*/) {
abstract fun printColor()
}
class Blue {
val color = "blue"
}
class BlueColor(t: Blue) : Color<Blue>(t) {
override fun printColor() {
println("color:${t.color}")
}
}
kotlin中可以通过out与in的关键字,指定泛型的上限和下限
标注允许传入 T 及 T的子类
// 系统的类ArrayList声明了一个泛型T
class ArrayList<T>{
}
// Type mismatch.Required: ArrayList , but Found:ArrayList
// 虽然Int是Number的子类,但kotlin认为ArrayList,不是 ArrayList的子类,所以会编译报错
val arrayList:ArrayList<Number> = ArrayList<Int>()//编译报错
// 在定义处使用out关键字声明,允许传入的泛型参数可以是T以及T的子类
class ArrayList<out T>{
}
// 也就是传入的泛型参数可以是 Number及Number的子类Int,Double,Float....
val arrayList:ArrayList<Number> = ArrayList<Int>()//编译正常
// 使用处使用out关键字声明
val arrayList:ArrayList<out Number> = ArrayList<Int>()//编译正常
标注可以传入 T或者T的父类
// 在定义处使用out关键字声明,允许传入的泛型参数可以是T以及T的子类
class ArrayList<T>{
}
val arrayList:ArrayList<Int> = ArrayList<Number>()//编译报错
class ArrayList<in T>{
}
// 也就是传入的泛型参数可以是 Number及Number的子类Int,Double,Float....
// 使用处使用out关键字声明
val arrayList:ArrayList<Int> = ArrayList<Number>()//编译正常
val arrayList:ArrayList<in Int> = ArrayList<Number>()//编译正常,此时in可写可不写
fun <T> fromJson(json: String, tClass: Class<T>): T? {
val t: T? = tClass.newInstance()
return t
}
fun main(){
var str = fromJson<String>("{}",String::class.java)
}
// 泛型类型限定-1
// 所传递的类型T必须满足是User的子类 或User类
// 类似于 Java中的 ? extends User
fun <T: User> fromJson(json: String, tClass: Class<T>): T? {
...
}
// 泛型类型限定-2
// 所传递的类型T必须同时满足 where 子句的所有条件,在下面的示例中,类型 T 必须既实现了 User, 也实现了 Comparable。
fun <T> fromJson(json: String, tClass: Class<T>): T? where T : User,T : Comparable<T> {
...
}
与Java创建的类有较大不同
class Ractangle(var height:Int,var width:Int)
fun main() {
var rectangle = Rectangle(5, 10)
println("矩形的高度是${rectangle.height}")
println("矩形的宽度是${rectangle.width}")
}
与Java不同的是 main方法好像不能写到类里边
class Girl(var name:String,var chactor:String,var voice:String){
fun smile(){
println("妹子笑声很${voice}")
}
fun status(){
println("妹子状态比较${chactor}")
}
}
fun main() {
var girl = Girl("测试", "彪悍", "甜美")
girl.smile()
girl.status()
}
与 java 类型,但是需要给出默认值
package net.lesscoding.oop
class WashMachine(var name:String,var size:Int) {
var isOpenDoor = true
var currentModel = 0
fun openDoor(){
this.isOpenDoor = true
println("打开洗衣机的门")
}
fun closeDoor(){
this.isOpenDoor = false
println("打开洗衣机的门")
}
fun startWash(){
if(!isOpenDoor){
when(currentModel){
1 -> println("开始轻柔的洗衣服")
2 -> println("开始狂暴的洗衣服")
else -> println("模式错误")
}
}else {
println("门没关")
}
}
fun chooseModel(model:Int){
this.currentModel = model
when(model){
1 -> println("轻柔模式")
2 -> println("狂暴模式")
else -> println("模式错误")
}
}
}
fun main() {
var washMachine = WashMachine("海尔", 5)
washMachine.openDoor()
washMachine.closeDoor()
washMachine.chooseModel(2)
washMachine.startWash()
}
相当于
java
中的private
private fun speed(speed:Int){
println("转速$speed")
}
相较于Java 感觉异常麻烦,如果你的类或者是方法想要被子类继承的话,需要添加
open
关键字
open class Fathor {
var chactor:String = "性格内向"
open fun action(){
println("公共场合喜欢大声呼喊")
}
}
使用
:Fathor()
代表继承父类 ,重写方法由@Override
变更为了override
关键字
class Son :Fathor(){
override fun action(){
println("喜欢安静")
}
}
和Java一样,但是如果父类有属性的话,需要写很多数据
abstract class Human (var name:String){
abstract fun eat()
}
这里继承父类也需要写上父类的属性,比较麻烦
class Man(name: String) :Human(name){
override fun eat() {
println("$name 喜欢大口大口的吃")
}
}
class Woman(name:String) :Human(name) {
override fun eat() {
println("$name 喜欢小口慢嚼")
}
}
fun main() {
var person1 = Man("普信男")
person1.eat()
var person2 = Woman("普信女")
person2.eat()
// 输出
//普信男 喜欢大口大口的吃
// 普信女 喜欢小口慢嚼
}
好像跟java也差不多
package net.lesscoding.oop.test03
interface IMan {
fun eat()
}
package net.lesscoding.oop.test03
class Man:IMan {
override fun eat() {
println("大口大口的吃")
}
}
fun main(){
var man = Man()
man.eat()
}
相当于是一个中间商啊
package net.lesscoding.oop.test04
interface IWashBow {
fun washing()
}
package net.lesscoding.oop.test04
class BigHeadSon :IWashBow{
override fun washing() {
println("大头儿子洗一次碗赚了1块")
}
}
在这个类中首先实现了接口
IWashBow
然后使用by
关键字委托BigHeadSon()
来实现washing()
方法
package net.lesscoding.oop.test04
class SmallHeadFather :IWashBow by BigHeadSon(){
}
当然这个类依旧可以实现接口的方法
package net.lesscoding.oop.test04
class SmallHeadFather :IWashBow by BigHeadSon(){
override fun washing() {
println("我要外包给大头儿子洗")
BigHeadSon().washing()
println("血赚9块钱")
}
}
SmallHeadFather
虽然让BigHeadSon
代理了接口实现,但是在类中调用了两次BigHeadSon()
,这就会创建两个BigHeadSon
对象,所以需要把BigHeadSon
变成单例的.只需要把
class
关键字换成object
即可。委托类需要修改一下生成
package net.lesscoding.oop.test04
object BigHeadSon :IWashBow{
override fun washing() {
println("大头儿子洗一次碗赚了1块")
}
}
package net.lesscoding.oop.test04
class SmallHeadFather :IWashBow by BigHeadSon{
override fun washing() {
println("我要外包给大头儿子洗")
BigHeadSon.washing()
println("血赚9块钱")
}
}
此时同时创建两个代理类比较内存地址为一样的
var bigHeadSon = BigHeadSon
var bigHeadSon2 = BigHeadSon
println(bigHeadSon == bigHeadSon2) //true
较为麻烦,还需要多写一个class, 且想要什么参数需要加在类的参数上
package net.lesscoding.oop.test05
// 注意这里如果不写var的话 下边第二个info就获取不出来
enum class Week(var index:Int,var info:String) {
Monday(1,"星期一"),
Tuesday(2,"星期二"),
Wednesday(3,"星期三"),
Thursday(4,"星期四"),
Friday(5,"星期五"),
Saturday(6,"星期六"),
Sunday(7,"星期日")
}
fun main() {
println(Week.Friday)
println(Week.Friday.info)
println(Week.Sunday.ordinal)
}
相当于是一个类里边有**数量有限**的子类,需要使用关键字
sealed
使用is
关键字代替 java中的instanceof
与 enum相比较 Sealed class更在意类型,枚举更在意数据
package net.lesscoding.oop.test05
sealed class Person {
fun say(){
println("Hello World")
}
class Man:Person()
class Woman:Person()
}
fun main(){
var man:Person = Person.Man()
var woman:Person = Person.Woman()
var man2:Person = Person.Man()
var personList = listOf<Person>(man, woman, man2)
for (person in personList) {
if(person is Person.Man){
person.say()
}
}
}
定义一个集合,包含20条数据
package net.lesscoding.stream
data class Girl(var name: String, var age: Int, var height: Int, var address: String)
var databaseTest = listOf<Girl>(
Girl("依儿", 18, 168, "山东"),
Girl("笑笑", 19, 175, "河南"),
Girl("小百合", 17, 155, "福建"),
Girl("michel", 22, 148, "广东"),
Girl("猫咪", 28, 159, "广西"),
Girl("玲儿", 23, 169, "广东"),
Girl("环环", 25, 172, "安徽"),
Girl("胖嘟嘟", 32, 180, "河北"),
Girl("乔乔", 35, 180, "广东"),
Girl("小可爱", 27, 150, "江西"),
Girl("一生有你", 22, 163, "山东"),
Girl("敏儿", 28, 155, "黑龙江"),
Girl("月儿", 25, 178, "吉林"),
Girl("花儿", 21, 183, "山东"),
Girl("s小糖", 49, 190, "新疆"),
Girl("悦悦", 19, 160, "广西"),
Girl("小可爱", 29, 158, "广东"),
Girl("紫琪", 49, 149, "新疆"),
Girl("糖心", 26, 165, "甘肃"),
Girl("棒棒糖", 23, 172, "浙江"),
Girl("猪猪侠", 18, 173, "山东"),
Girl("喵喵", 27, 164, "河南"),
Girl("安琦", 19, 159, "河北"),
Girl("叶子", 20, 160, "广东")
)
传统函数应对不同的需求,一般会复制出来不同的方法,需求越来越多的时候,函数就会变得越来越多,如下
fun findByAddress(address :String?){
for(girl in databaseTest){
if(girl.address.equals(address!!)){
println("${girl.address} ${girl.name}")
}
}
}
fun findLessAge(age:Int){
for(girl in databaseTest){
if(girl.age < age){
println("${girl.address} ${girl.name} ${girl.age}")
}
}
}
可以看到在kotlin中可以使用 and关键字代替 && 但是需要用括号将后边的包起来,同样的还有 or ( || ) xor (^) 等
fun findByAddressAgeHeight(address: String,age: Int,height: Int){
for(girl in databaseTest){
if(girl.age < age && girl.address.equals(address) and (girl.height > height)){
println("${girl.address} ${girl.name} ${girl.age} ${girl.height}")
}
}
}
跟
java
中的stream
流相差不大,但是里边的对象都必须用it表示
按照某一个属性求最大值
// 按照年龄字段排序取最大值
var maxAgeGirl = databaseTest.maxBy { it.age }
按照某一属性求最小值
//按照height字段取最小值的对象
var minAgeGirl = databaseTest.minBy { it.height}
过滤集合中的数据,返回一个boolean类型的值
// 过滤年龄小于20且身高在165以上的数据
var filterList = databaseTest.filter {
it.age < 20 && it.height >= 165
}
把某个属性映射成新的集合
//把集合中的名称拿出来做一个集合
var nameList = databaseTest.map { it.name}
按照条件查询集合,如果有的话返回true 没有的话返回false
// 判断集合中有没有元素的age属性是18
var ageFlag = databaseTest.any { it.age == 18}
查找集合中符合条件的元素的个数
//查找age < 20的个数
var ageLess20 = databaseTest.count{ it.age < 20}
查找第一个符合条件的元素
var firstGuangDong databaseTest.find{ it.address == "广东"}
查找最后一个符合条件的元素
var lastGuangDong = databaseTest.findLast {it.address == "广东"}
按照某个属性分组,返回一个Map,可以同个get方法获取里边的值
var groupByAddress = databaseTest.groupBy { it.address }
给集合添加拓展函数
fun List<Girl>.findByAgeLess(age :Int) {
filter { it.age < age }.forEach(::println)
}
databaseTest.findByAgeLess(20)
使用
infix
关键字可以将方法调用中的.
省略掉替换成空格
infix fun List<Girl>.findByAgeLess(age :Int) {
filter { it.age < age }.forEach(::println)
}
databaseTest findByAgeLess 20
class Jump {
fun test() {
println("jump test")
//在被扩展的类中使用
doubleJump(1f)
}
}
fun Jump.doubleJump(howLong: Float): Boolean {
println("jump:$howLong")
println("jump:$howLong")
return true
}
Jump().doubleJump(2f)
//在被扩展类的外部使用
Jump().test()
在
Android Studio
中点击Tools
,然后点击Kotlin --> Show Kotlin Bytecode
,最后点击Decompile就可以查看kotlin编译之后的java文件
KotlinExtensionKt.doubleJump(new Jump(), 2.0f);
//泛型化扩展函数
fun <T> MutableList<T>.swap1(index1: Int, index2: Int) {
val tmp = this[index1]
this[index1] = this[index2]
this[index2] = tmp
}
val test2 = mutableListOf("Android Q", "Android N", "Android M")
test2.swap1(0,1)
println(test2)
扩展属性提供了一种方法能通过属性语法进行访问的API来扩展。尽管它们被叫做属性,但是它们不能拥有任何状态,它不能添加额外的字段到现有的Java对象实例。
//为String添加一个lastChar属性,用于获取字符串的最后一个字符
// Kotlin中任何属性都有get 和 set方法
val String.lastChar: Char get() = this.get(this.length - 1)
///为List添加一个last属性用于获取列表的最后一个元素,this可以省略
val <T>List<T>.last: T get() = get(size - 1)
val listString = listOf("Android Q", "Android N", "Android M")
println("listString.last${listString.last}")
就像伴生对象的常规成员一样:可以只使用类名作为限定符来调用伴生对象的扩展成员:
class Jump {
companion object {}
}
fun Jump.Companion.print(str: String) {
println(str)
}
Jump.print("伴生对象的扩展")
// kotlin中对let的定义
fun <T, R> T.let(f: (T) -> R): R = f(this)
let扩展函数的实际上是一个作用域函数,当你需要去定义一个变量在一个特定的作用域范围内,那么let函数是一个不错的选择;let函数另一个作用就是可以避免写一些判断null的操作。
fun main() {
letTest("123")
letTest(null)
}
fun letTest(str: String?){
str.let {
var str2 = "Android"
println("$str2 it")
}
str?.let {
println("$it 的长度是 ${it.length}")
}
}
// kotlin中对let的定义
fun <T, R> T.run(f: T.() -> R): R = f()
run函数只接收一个lambda函数为参数,以闭包形式返回,返回值为最后一行的值或者指定的return的表达式,在run函数中可以直接访问实例的公有属性和方法。
data class Room(val address: String, val price: Float, val size: Float)
fun testRun(room: Room) {
room.run {
println("Room:$address,$price,$size")
}
}
调用apply方法之后, 就不需要通过对象.方法了 ,可以直接使用方法
调用某对象的apply函数,在函数范围内,可以任意调用该对象的任意方法,并返回该对象。
从结构上来看apply函数和run函数很像,唯一不同点就是它们各自返回的值不一样,run函数是以闭包形式返回最后一行代码的值,而apply函数的返回的是传入对象的本身。
class Person{
fun eat(){
println("吃饭")
}
fun drink(){
println("喝水")
}
}
fun main(){
var person = Person()
// 平常写法
person.eat()
person.drink()
//使用apply
person?.apply {
eat()
drink()
}
}
fun testApply(){
ArrayList<String>().apply {
add("111")
add("222")
add("2223")
// apply内部有一个隐式的对象 this
println("$this")
}.let {
println(it)
}
}
使用Kotlin扩展为控件绑定监听器减少模板代码
// 为Activity定义find扩展方法,通过资源id获取控件
fun <T: View> Activity.find(@IdRes id: Int): T{
return findViewById(id)
}
// 为Int添加onClick扩展方法,用于为资源id对应的空间添加onClick监听
fun Int.onClick(activity: Activity,click: () -> Unit){
activity.find<View>(this).apply {
setOnClickListener {
click()
}
}
}
class MainActivity: AppCompatActivity{
override fun onCreate(saveInstanceState: Bundle?){
super.onCreate(saveIntanceState)
// 绑定对应的xml资源文件
setContentView(R.layout.activity_main)
// 查询id是test的文本框
val textView = find<TextView>(R.id.test)
R.id.test.onClick(this){
textView.text = "Kotlin扩展应用"
}
}
}
package com.example.myapplication.test
import kotlin.system.exitProcess
fun main(){
while (true){
println("====请输入算术表达式====")
var calcStr = readLine()
println(calcSplit(calcStr))
println("是否继续,(y/n)")
var choose = readLine()
if(choose.equals("n",true)){
println("系统退出")
exitProcess(0)
}
}
}
fun calcSplit(calcStr: String?): String{
calcStr?.let {
var symbol :String = ""
if(it.contains("+")){
symbol = "+"
}
if(it.contains("-")){
symbol = "-"
}
if(it.contains("*")){
symbol = "*"
}
if(it.contains("/")){
symbol = "/"
}
var split = it.split(symbol)
return calc(split,symbol).toString()
}
return "算术表达式错误"
}
fun calc(split:List<String>,symbols: String): Double{
var firstNumber = split[0].toDouble()
var lastNumber = split[1].toDouble()
return when(symbols){
"+" -> firstNumber + lastNumber
"-" -> firstNumber - lastNumber
"/" -> firstNumber / lastNumber
"*" -> firstNumber * lastNumber
else -> 0.0
}
}
vity.find(this).apply {
setOnClickListener {
click()
}
}
}
- 使用扩展
```kotlin
class MainActivity: AppCompatActivity{
override fun onCreate(saveInstanceState: Bundle?){
super.onCreate(saveIntanceState)
// 绑定对应的xml资源文件
setContentView(R.layout.activity_main)
// 查询id是test的文本框
val textView = find(R.id.test)
R.id.test.onClick(this){
textView.text = "Kotlin扩展应用"
}
}
}
package com.example.myapplication.test
import kotlin.system.exitProcess
fun main(){
while (true){
println("====请输入算术表达式====")
var calcStr = readLine()
println(calcSplit(calcStr))
println("是否继续,(y/n)")
var choose = readLine()
if(choose.equals("n",true)){
println("系统退出")
exitProcess(0)
}
}
}
fun calcSplit(calcStr: String?): String{
calcStr?.let {
var symbol :String = ""
if(it.contains("+")){
symbol = "+"
}
if(it.contains("-")){
symbol = "-"
}
if(it.contains("*")){
symbol = "*"
}
if(it.contains("/")){
symbol = "/"
}
var split = it.split(symbol)
return calc(split,symbol).toString()
}
return "算术表达式错误"
}
fun calc(split:List<String>,symbols: String): Double{
var firstNumber = split[0].toDouble()
var lastNumber = split[1].toDouble()
return when(symbols){
"+" -> firstNumber + lastNumber
"-" -> firstNumber - lastNumber
"/" -> firstNumber / lastNumber
"*" -> firstNumber * lastNumber
else -> 0.0
}
}