安装方式
- 使用方法
scoop install kotlin
等待完成就完成部署了,连环境变量都可以不用修改了
内置类型
基本类型
类型 | 大小(比特数) | 最小值 | 最大值 |
---|---|---|---|
Byte | 8 | -128 | 127 |
Short | 16 | -32768 | 32767 |
Int | 32 | -2,147,483,648 (-231) | 2,147,483,647 (231 – 1) |
Long | 64 | -9,223,372,036,854,775,808 (-263) | 9,223,372,036,854,775,807 (263 – 1) |
- long形容数字的话,末尾必须是大写
L
- 无法默认类型转化,int的变量无法直接赋值给long 必须显示的调用
val f = e.toLong()
- 所有类型和java的基础类型差不多,就是首字母是大写的而已,
Int Double Float String Byte
这类 - 有无符号类型,
UInt
,在上面的基础类型前面加上 U - 字符串可以使用
$
来添加"value of String j is = $j"
如果使用对象函数调用的话使用大括号括起来"length of String j is:${j.length}"
println("Range of UInt [${UInt.MIN_VALUE}, ${UInt.MAX_VALUE}]")
- 不需要 new 了
===
对比的是引用;==
相当于 java的equals
函数- Row String 的引用
val n = """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>网站标题</h1>
</body>
</html>
""".trimIndent()
trimIndent 这个函数主要是去除公共空格
<!-- 这前面的四个空格或者tab就是公共空格 --><!DOCTYPE html>
<html lang="en">
<head>
val
和var
的区别是val
修饰的变量类似于java变量前面加上final
var
修饰的变量有自动类型推导功能,可以使用ide显示出来类型
- kotlin定义变量的方式是:
var 变量名: 变量类型 = 变量值
但是这种方式可以使用var 变量名 = 变量值
来代替 - 如果需要声明一个空的变量,
var 变量名: 变量类型?
就可以
数字
Long
末尾使用L
类型 | 大小(比特数) | 有效数字比特数 | 指数比特数 | 十进制位数 |
---|---|---|---|---|
Float | 32 | 24 | 8 | 6-7 |
Double | 64 | 53 | 11 | 15-16 |
Float
末尾使用f
或者F
标记一个数字- 小数点出现默认类型为
Double
- 十六进制
0x0F
- 二进制
0b00001011
- 不支持八进制
数字字面值中的下划线
val oneMillion = 1_000_000
val creditCardNumber = 1234_5678_9012_3456L
val socialSecurityNumber = 999_99_9999L
val hexBytes = 0xFF_EC_DE_5E
val bytes = 0b11010010_01101001_10010100_10010010
==
equals 方法比较,===
引用类型比较?
操作符只有前面的a
不为null
时才可以计算后面的方法a?.length
!!
符号表示判断该变量是否为null
, 为null
这抛出异常kotlin.KotlinNullPointerException
is
或者!is
是否为某个类型, 经过is
判断如果成功, 变量就会变成is
之后的类型Any
就相当于 java 中的Object
类
val a: Int = 10000
println(a === a)
// 使用 类型? 就有装箱的情况
val boxedA: Int? = a
val anotherBoxedA: Int? = a
println("boxedA = $boxedA")
println("anotherBoxedA = $anotherBoxedA")
println(boxedA === anotherBoxedA) // 引用比较 false
println(boxedA == anotherBoxedA) // equals 方法比较 true
val str = 10000
val str1: Int? = str
val str2: Int? = str
println(str1 == str2) // equals 方法比较 true
println(str1 === str2) // 引用比较 false
if (str is String) {
// 如果 str 原本是 Any 类型, 如果使用了 is 关键字则隐含着表示这个对象转化成 String 类型
return str.toUpperCase()
}
- as` 不安全类型转化
val x: String = y as String
// 这里 如果y
为空就会抛出异常, 则无法转化成String
val x: String? = y as String?
// 这样 如果y
为空就不会转化成String, 但是它如果无法转化会抛出异常 安全的可空转化操作方式 val x: String? = y as? String
// 失败返回 null
这里 x
时可空类型, 不会抛出异常
val a:Any = 100
val b1 = a as? String
// val b2 = a as String? // 抛出异常
println("b1 = $b1") // 类型 b1 ===> String?
// println("b2 = $b2") // 类型 b2 ===> String?
- kotlin 已经一般的隐式转换需要调用方法转化
toByte(): Byte
toShort(): Short
toInt(): Int
toLong(): Long
toFloat(): Float
toDouble(): Double
toChar(): Char
kotlin在计算中的隐式转化
// 这种隐式转化也是可以的
val c: Int = 10
val d: Byte = 3
val e: Int = c + d
println("e = $e")
运算
整数运算
整数除法
val x = 5 / 2
println(x == 2) // true
val y = 5L / 2
println(y == 2L) // true
val z = 5 / 2.toDouble()
println("z val is $z") // 2.5
println(z == 2.5) // true
- 位运算
// 位运算
val x = (1 shl 2) // 左移 2 位
println("x = $x")
val y = x and 0x000FF000
println("y = $y")
这是完整的位运算列表(只用于 Int
与 Long
):
shl(bits)
– 有符号左移shr(bits)
– 有符号右移ushr(bits)
– 无符号右移and(bits)
– 位与or(bits)
– 位或xor(bits)
– 位异或inv()
– 位非
- 浮点数比较
相等性检测:
a == b
与a != b
比较操作符:a < b
、a > b
、a <= b
、a >= b
区间实例以及区间检测:a..b
、x in a..b
、x !in a..b
- 字符需要注意
\$
这个用法 - Elvis语句 ( 如果空, 则走另一个 )
val res = 表达式1 :? 表达式2
如果表达式1
的结果是null, 则执行表达式2
的语句, 结果(res
)就是表达式的结果了
val map = mapOf("1" to "2", "3" to "4", "5" to "6")
val get = map["2"] ?: map["5"] // 这里 map["2"] 为空, 则走 map["5"] 最终返回 6
println("map[2] = $get")
kotlin 包名可以和``public`类对象不同
- kotlin中的包和java 不一样, 不需要包在哪,. 程序的包名就叫什么 kotlin 包名:
package com.zhazha2121212
实际的类在com.zhazha
下 但是这个类编译后的路径在:build\classes\kotlin\main\com\zhazha2121212
- 给包取别名
import com.zhazha.other.multiply as myMultiply
/**
*
* Create by zhazha on 2020-05-23
*/
fun multiply(a: Int, b: Int) = a * b
// other file
import com.zhazha.other.multiply
import com.zhazha.other.multiply as myMultiply
private fun func03Import() {
println(multiply(10, 5))
println(myMultiply(10, 6))
}
逻辑操作符
if 使用方法
- kotlin中没有三目运算符, 但是可以使用
if expression res1 else res2
private fun maxMinFuncUp() {
var x: Double = 2444.0
var y: Double = 25555.0
var max: Double = if (x > y) x else y
var min: Double = if (x > y) y else x
println("max = $max, min = $min")
}
private fun maxMinFunc02() {
var x: Long = 1000L
var y: Long = 200L
var max: Long = if (x > y) {
println("max = $x")
x
} else {
println("min = $y")
y
}
var min: Long = if (x > y) {
println("min = $y")
y
} else {
println("max = $x")
x
}
println("max = $max, min = $$min")
}
private fun maxMinFunc01() {
var x: Int = 10
var y: Int = 20
var max: Int = 0
var min: Int = 0
if (x > y) {
max = x
min = y
} else {
min = x
max = y
}
println("max = $max, min = $min")
}
- if 表达式使用, if 可以直接赋值
val max = if (a > b) a else b
/**
* if 表达式
*/
fun ifExpression(a: Int, b: Int): Int {
return if (a > b) a else b
}
- ★注意下面这种用法, 在末尾添加直接写上变量, 则表示返回值
/**
* if 表达式
*/
fun ifExpression2(a: Int, b: Int): Int {
val max = if (a > b) {
println("max is a , a = $a")
a
} else {
println("max is b, b = $b")
b
}
return max
}
数组
kotlin的数组也是包含基础和装箱类型 单纯的使用 Array<Int>
这种就是装箱方案
使用 IntArray
或者 CharArray
等都是基础方案
/**
* 数组的创建
*/
println("数组创建:")
val array = IntArray(5) { it + 1 }
val array1 = IntArray(5, init = { it + 1 })
println(array.contentToString())
println(array1.contentToString())
val arr = intArrayOf(1, 2, 3, 4, 5)
println(arr.contentToString())
/**
* 数组的长度
*/
println("数组长度:")
val size = IntArray(5).size
println("数组长度是:$size")
/**
* 数组的读写
*/
val strArr = arrayOf("hello", "world")
println(strArr.contentToString())
strArr.forEach { s -> println(s) }
strArr[1] = "Kotlin"
println("${strArr[0]}, ${strArr[1]}")
/**
* 数组遍历
*/
val floats = floatArrayOf(1f, 3f, 5f, 7f)
for (fl in floats) {
println(fl)
}
floats.forEach { fl -> println(fl) }
/**
* 数组包含关系
* 判断数组内部是否存在值未 1f 的元素
*/
if (1f in floats) {
println("1f exists in variable 'floats' ")
}
/**
* 不包含
*/
if (20f !in floats) {
println("20f not exists in variable 'floats'")
}
区间
- 1 .. N [1, N]
- N downTo 1 [N, N – 1, .. , 1]
- 1 until N [1, N)
- 1 .. 8 step 2 // 步长
/**
* 闭区间
* 区间从小到大
*/
val intRange = 1..10 // [1, 10]
val charRange = 'a'..'z' // ['a', 'z']
val longRange = 1L..100L // [1L, 100L]
// intRange.forEach(Consumer { t -> println(t) })
// intRange.forEach { t -> print("$t ") }
println(intRange.joinToString())
/**
* 先开后闭区间
* 区间值从小到大
*/
val intRangeExclusive = 1 until 10 // [1, 10)
val charRangeExclusive = 'a' until 'z' // ['a', 'z')
val longRangeExclusive = 1L until 100L // [1L, 100L)
// intRangeExclusive.forEach { t: Int? -> print("$t ") }
println(intRangeExclusive.joinToString())
/**
* 反向迭代闭区间
* 区间值从大到小
*/
val intRangeReverse = 10 downTo 1 // [10, 9, .. , 1]
val charRangeReverse = 'z' downTo 'a' // a ~ z
val longRangeReverse = 100L downTo 1L // 1L ~ 100L
// intRangeReverse.forEach { t: Int? -> print("$t ") }
println(intRangeReverse.joinToString())
/**
* 区间步长
*/
val intRangeWithStep = 1..10 step 2
val charRangeWithStep = 'a'..'z' step 2
val longRangeWithStep = 1L..100L step 2
// intRangeWithStep.forEach { t: Int? -> print("$t ") }
println(intRangeWithStep.joinToString())
/**
* 区间的应用
*/
println("区间的应用: ")
val arrayOf = intArrayOf(1, 3, 5, 7)
// for (i in 0 until arrayOf.size) {
// println(arrayOf[i])
// }
for (i in arrayOf.indices) {
println(arrayOf[i])
}
list.indices
集合区间 –> 0..array.size - 1
遍历数组的方法
val m = intArrayOf(1, 2, 3)
// m.set(1, 4)
m[1] = 5
// for (v in m) {
// println("v = $v")
// }
// 迭代器
// val iterator = m.iterator()
// while (iterator.hasNext()) {
// println(iterator.nextInt())
// }
// lmabda
// m.forEach { println(it) }
// 直接使用数组的方法
// println(m.contentToString())
// 返回前N个元素, 不包括index那个元素 [0, index)
// println(m.take(2))
println(m.joinToString())
- 数组
IntArray
是java的int[]
其遍历方法是
// 定义并初始化一个数组
val arrays = intArrayOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 0)
for (array in arrays) {
println(array)
}
println("---------------------")
arrays.forEach { println(it) }
println("---------------------")
for (index in arrays.indices) {
println("array[$index] = ${arrays[index]}")
}
println("---------------------")
for ((index, value) in arrays.withIndex()) {
println("index = $index, array[index] = ${arrays[index]}, value = $value")
}
集合
- 复用 java API
- 提供丰富易用方法
- 运算符级别的支持, 简化集合框架的访问
typealias别名
typealias ArrayList<E> = java.util.ArrayList<E>
该类和java类相同
直接使用操作符对集合进行操作
可以用 -=
+=
[]
对集合进行操作 Map 类型可以直接利用数组完成 map['HashMap'] = 1
Map集合遍历隐含的类 Pair 和 Triple
pair
val pair = "Hello" to "World"
val pair2 = Pair("Hello", "World")
first = pair.first
fun main() {
val x = "aaa"
val y = "2"
println(printProduct(x, y))
val hashMap = hashMapOf("1" to 1, "2" to 2, "3" to 3)
// val a = hashMap.get("4")
val a = hashMap["4"] // a == null
val res = a?.plus(1) // null 加上了 ? 之后任何计算都是 null???
println(res) // null
if (null == res) {
println("res is null")
}
// res!! // kotlin.KotlinNullPointerException
}
fun parseInt(str: String) = str.toIntOrNull()
fun printProduct(str1: String, str2: String): Int? {
val num1 = parseInt(str1)
val num2 = parseInt(str2)
return num1?.plus(num2!!)
}
Triple
则表示三个参数时使用
字符串模板
val i = 10
println("i = $i") // // prints "i = 10"
调用函数的话
val s = "string"
println("$s.length is ${s.length}")
如果 $
需要被打印出来
val price = """
${'$'}9.99
"""
kotlin 类
kotlin构造方法
kotlin 的类存在两种构造方法
-
primary
构造方法: 这种构造方法只能有一个secondary
构造方法: 这种构造方法可以有多个或者没有
class EmptyClass
// 这种在类旁边写上初始化的方式, 就是 primary 构造方法
class MyClass constructor(username: String) {
private var username: String = username.toUpperCase()
init {
println(this.username)
// 这个就相当于初始化代码块
this.username = username
println(this.username)
}
}
fun main() {
val myClass = MyClass("zhazha")
println(myClass)
}
- 构造方法
// 空类是可以存在的
class EmptyClass
class MyClass constructor(username: String) {
private var username: String = username.toUpperCase()
// secondary构造函数需要主动调用 primary 构造函数, 或者调用另一个调用了primay构造方法的secondary构造方法
// constructor() {
constructor() : this("") {
println("无参数构造函数")
}
// 类都存在一个 init 方法, 在调用 primary 构造方法时才会使用到
init {
println(this.username)
// 这个就相当于初始化代码块
this.username = username
println(this.username)
}
}
fun main() {
val myClass = MyClass("zhazha")
println(myClass)
// secondary构造函数需要主动调用 primary 构造函数
val myClass1 = MyClass()
println(myClass1)
}
class Student10(username: String, age: Int, money: Double) {
var username: String
var age: Int
var money: Double
init {
this.username = username
this.age = age
this.money = money
}
}
class Student10_1(username: String, age: Int, money: Double) {
var username: String
// 设置了属性 username 不可 set (赋值功能)
private set
var age: Int
private set
var money: Double
private set
init {
this.username = username
this.age = age
this.money = money
}
}
class Person constructor(username: String) {
private var username: String
private var age: Int
private var address: String
private var money: Double
init {
this.username = username
this.age = 20
this.address = "beijing"
this.money = 10_0000.0
}
constructor(age: Int) : this("") {
this.age = age
}
constructor(money: Double) : this("") {
this.money = money
}
constructor(username: String, money: Double) : this(username) {
this.money = money
}
constructor(username: String, age: Int) : this(username) {
this.age = age
}
constructor(username: String, age: Int, address: String) : this(username, age) {
this.address = address
}
fun printInfo() {
println("username = ${this.username}, age = ${this.age}, address = ${this.address}, money = ${this.money}")
}
}
fun main() {
val student10 = Student10("zhazha", 12, 100_0000.0)
println(student10)
val student101 = Student10_1("1111", 11, 11111111.0)
println(student101)
println(student101.money)
println(student101.username)
println(student101.age)
val person0 = Person("zhazha")
val person1 = Person(10)
val person2 = Person(1000_0000.0)
val person3 = Person("zhazha", 1000_0000.0)
val person4 = Person("zhazha", 20)
val person5 = Person("zhazha", 7, "beijing")
person0.printInfo()
person1.printInfo()
person2.printInfo()
person3.printInfo()
person4.printInfo()
person5.printInfo()
}
/**
* 在类旁边使用了 private var username: String 字段就相当于在类内部添加了个属性
*/
class Student(private var username: String, private var age: Int, private var address: String) {
fun printInfo() {
println("username = $username, age = $age, address = $address")
}
}
/**
* 如果构造方法有注释或者关键字, 构造方法关键字则不能省略
*/
class Student2 private constructor(username: String)
/**
* 如果primary构造方法的所有参数都有默认值, 那么这个kotlin就会为这个类添加一个无参数构造函数
* 这里的 username 默认是 public 关键字
*/
class Student3(var username: String = "zhazha")
fun main() {
val student = Student("heihei", 22, "beijing")
student.printInfo()
var student3 = Student3()
println(student3.username)
student3 = Student3("gggggggg") // 这里可以赋值
println(student3.username)
}
类的继承
字段继承和方法继承
open class Person1(name: String, age: Int)
// 类似于c++的初始化成员列表
class Child(name: String, age: Int) : Person1(name, age)
open class Person2(name: String)
class Child2 : Person2 {
// super 调用父类的构造方法
constructor(name: String) : super(name)
}
fun main() {
val person1 = Person1("zhazha", 111)
println(person1)
val child = Child("heihei", 12)
println(child)
val person2 = Person2("xixi")
println(person2)
val child2 = Child2("gun")
println(child2)
}
继承遇到函数相同的情况下便是重写
open class Fruit {
open fun print() {
println("fruit")
}
fun expirationData() {
println("1 day")
}
}
class Apple : Fruit() {
override fun print() {
super.print()
println("apple")
}
}
class Orange : Fruit() {
// 防止Orange的之类发生重写
override fun print() {
super.print()
println("Orange")
}
}
fun main() {
val apple = Apple()
println("apple = $apple")
apple.expirationData()
val orange = Orange()
println(orange)
}
字段重写以及set/get方法权限的设置
open class MyParent {
open val name: String = "parent"
}
// val 修饰的字段可以被重写成var字段
class MyChild : MyParent() {
override var name: String = "child"
}
class MyChild2(override val name: String = "mychild2") : MyParent()
fun main() {
val myChild = MyChild()
println(myChild)
val myChild2 = MyChild2()
println(myChild2)
val myParent2 = MyParent2("zhazh2")
println(myParent2)
val myChild02 = MyChild02("zhazhaChild")
println(myChild02)
}
open class MyParent2(open var name: String = "MyParent2") {
open fun method() {
println("parent method")
}
}
/**
* 父 val 字段 子类可以为 var, 反之不行
*/
class MyChild02(name: String) : MyParent2(name) {
override fun method() {
super.method()
println("MyChild02")
}
override var name: String = ""
get() = super.name + "MyChild02"
set(value) {
field = value
}
}
属性的get/set方法和属性真实field
class ThePerson(address: String, name: String) {
val age: Int
get() = 20
var address: String = address
get() {
println("get() address")
return field // 其内部真实的字段是 field
}
set(value) {
println("set() address")
field = value // 其内部真实的字段是 field
}
// name 字段默认提供 get/set 方法. 成为属性
var name: String = name
private set // 设置 set 方法不被外界调用
}
fun main() {
// 对 kotlin 属性的修改和读取都是使用的 get/set 方法
val thePerson = ThePerson("shanghai", "zhangsan")
println(thePerson.age)
println(thePerson.address)
thePerson.address = "beijing"
println(thePerson.address)
println(thePerson.name)
// thePerson.name = "ddddddddddddddd" // 这个方法被 private set
}
接口和多继承, 遇到父类相同方法实现
interface ParentA {
fun method()
fun method2() {
println("com.zhazha.ParentA.method2: 父类方法存在自己的方法体, 所以子类不需要重写")
}
fun method3() {
println("com.zhazha.ParentA.method3: 父类方法 A 存在两个相同方法")
}
fun method4();
}
open class ParentC {
open fun method3() {
println("com.zhazha.ParentC.method3: 父类方法 C 存在两个相同的方法")
}
open fun method4() {
println("com.zhazha.ParentC.method4: 如果类ParentA的method4方法没实现, 那么他会调用哪个方法???")
}
}
/**
* 类 B 多实现 方法 method3 必须明确指出是哪个父类的方法, 使用 super<A> 或者 super<B> 这两个方法一起实现
*/
class ChildB : ParentA, ParentC() {
override fun method() {
println("com.zhazha.ChildB.method: 如果接口的方法没有方法体, 则子类需要实现方法")
}
override fun method2() {
super.method2()
println("com.zhazha.ParentA.method2: 即使父类存在方法体的方法实现, 子类还是可以重写这个方法")
}
override fun method3() {
super<ParentA>.method3()
super<ParentC>.method3()
println("com.zhazha.ChildB.method3: 子类同时调用了父类和子类的这个method3方法")
}
override fun method4() {
super.method4()
println("子类只能使用实现了method4方法类的方法")
}
}
fun main() {
val b = ChildB()
b.method()
b.method2()
b.method3()
b.method4()
}
对象类和伴生对象
半生类其实类似于java的静态方法和字段
/**
* 这个是无法用在单例上的
*/
object MyObject {
fun method() {
println("这是一个对象类. 可能也是一个单例哦")
}
}
class MyTest16 {
// 伴生对象只有一个
// companion object MyCompanion {
// }
// 伴生对象名字可以省略, 如果省略不写, 则默认名字是 Companion
// companion object MyCompanion {
companion object {
private var a: Int = 100
var b: Int = 1000
fun method() {
println("companion object method")
}
@JvmStatic
fun methodStatic() {
println("static func method")
methodPrivate()
}
// 这个方法是外面无法调用的
private fun methodPrivate() {
println("this is private method ")
}
}
}
fun main() {
// 测试对象类是否为单例
// checkSingleton()
MyTest16.method()
MyTest16.methodStatic()
MyTest16.Companion.method()
MyTest16.Companion.methodStatic()
println(MyTest16.b)
}
/**
* 对象类的单例检测是不可以的
*/
private fun checkSingleton() {
val clazz = MyObject.javaClass
val constructor = clazz.getDeclaredConstructor()
if (constructor.trySetAccessible()) {
val instance = constructor.newInstance()
if (instance == MyObject) {
println("true 0")
} else if (instance === MyObject) {
println("true 1")
} else {
println("但不是单例")
}
instance.method()
}
MyObject.method()
}
字段的延迟加载
// 主构造函数参数上不允许使用“ lateinit”修饰符
class TheClass(val age: Int = 1000) {
// 延迟加载属性, 这个lateinit关键字好像不支持基础类型
lateinit var username: String
init {
println("真正初始化方法被调用")
}
fun init() {
this.username = "zhangsan"
println("用户定义的init方法")
}
fun print() {
println(this.username)
}
}
fun main() {
val theClass = TheClass(1)
println(theClass.age)
theClass.init()
theClass.print()
println(theClass.username)
}
lateinit
不能用于基础类型, 不能用于带?
的类型, 不能定义 set/get
方法
- 扩展方法(帮类添加一个扩展方法)
- 不修改真实类的方法
- 无多态, 纯静态操作
- 结果只看声明类型, 不看实际类型
open class A
class B : A()
fun A.a() = "a"
fun B.a() = "b"
fun printW(a: A) {
println(a.a())
}
fun main() {
// 扩展方法它是静态的, 没有多态
// 不会添加扩展方法到类中
// 没有多态, 所以结果看声明类型, 不看动态类型(实际类型)
printW(B()) // 打印是 a
}