Kotlin 是一种在 Java 虚拟机上运行的静态类型编程语言,被称之为 Android 世界的Swift,由 JetBrains 设计开发并开源。 Kotlin 可以编译成Java字节码,也可以编译成 JavaScript,方便在没有 JVM 的设备上运行。 在Google I/O 2017中,Google 宣布Kotlin成为 Android 官方开发语言。
参考视频:https://www.bilibili.com/video/BV1SY411y7T8/?spm_id_from=333.337.search-card.all.click
/**
* @description: 程序入口
* @author: shu
* @createDate: 2023/7/31 13:08
* @version: 1.0
*/
// 总结:
// 1. main函数的参数是一个字符串数组
// 2. main函数的返回值是Unit类型,相当于Java中的void
// 3. main函数的参数可以通过命令行传递
// 4. main函数可以省略不写
fun main(args: Array<String>) {
println(args.contentToString())
}
//fun main() {
// println("Hello World!")
//}
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
我们可以看到,Kotlin 的代码比 Java 的代码简洁很多,而且 Kotlin 的代码更加符合人类的思维,更加容易阅读,下面我们来看看 Kotlin 的基本语法。
/**
* @description:
* @author: shu
* @createDate: 2023/7/31 14:15
* @version: 1.0
*/
class VariableTest {
// 总结:
// 1. 变量的格式:var 变量名: 变量类型 = 变量值
// 2. 变量的类型可以省略不写,由编译器自动推断
// 3. 变量的类型可以省略不写,但是变量的值不能省略不写
// 4. 变量的类型可以省略不写,但是变量的值不能省略不写,变量的值可以通过后面的赋值语句赋值
var name: String = "张三"
var age: Int = 18
var height: Double = 1.75
var isMarried: Boolean = false
}
fun main(args: Array<String>) {
val variableTest = VariableTest()
println("姓名:${variableTest.name}")
println("年龄:${variableTest.age}")
println("身高:${variableTest.height}")
println("婚否:${variableTest.isMarried}")
// 不指定类型,由编译器自动推断
var name = "李四"
var age = 20
var height = 1.80
var isMarried = true
// 指定类型,不允许修改
val name1: String = "王五"
val age1: Int = 22
val height1: Double = 1.85
val isMarried1: Boolean = false
println("姓名:${name}")
println("年龄:${age}")
println("身高:${height}")
println("婚否:${isMarried}")
println("姓名:${name1}")
println("年龄:${age1}")
println("身高:${height1}")
println("婚否:${isMarried1}")
// 指定类型,不赋值,由编译器自动推断
val name2: String
val age2: Int
val height2: Double
val isMarried2: Boolean
name2 = "赵六"
age2 = 24
height2 = 1.90
isMarried2 = true
println("姓名:${name2}")
println("年龄:${age2}")
println("身高:${height2}")
println("婚否:${isMarried2}")
}
// 定义变量
String name = "张三";
int age = 18;
double height = 1.75;
boolean isMarried = false;
// 定义常量
final String name1 = "李四";
final int age1 = 20;
final double height1 = 1.80;
final boolean isMarried1 = true;
我们可以一发现变量的定义,Kotlin 比 Java 的代码简洁很多,而且 Kotlin 的代码更加符合人类的思维,更加容易阅读,但是这只是正对学习 Kotlin 的人来说,对于 Java 开发者来说,Java 的代码更加容易阅读。
注意点:
只要可以,应尽量在 Kotlin 中首选使用 val 不变值。因为在程序中大部分地方只需要使用不可变的变量,而使用 val 变量可以带来可预测的行为和线程安全等优点。
流程控制语句是编程语言中的核心之一,可分为:
package Controller
/**
* @description:
* @author: shu
* @createDate: 2023/7/31 21:12
* @version: 1.0
*/
class IF {
/**
* if语句
*/
fun isScore(score: Int): String {
return if (score >= 90) {
"优秀"
} else if (score >= 80) {
"良好"
} else if (score >= 70) {
"中等"
} else if (score >= 60) {
"及格"
} else {
"不及格"
}
}
}
fun main() {
val iF = IF()
println(iF.isScore(90))
}
when (变量) {
取值1 -> 代码块1
取值2 -> 代码块2
取值3 -> 代码块3
...
else -> 代码块n
}
when (x) {
in 1..10 -> print("x is in the range")
in validNumbers -> print("x is valid")
!in 10..20 -> print("x is outside the range")
else -> print("none of the above")
}
package Controller
/**
* @description:
* @author: shu
* @createDate: 2023/7/31 22:30
* @version: 1.0
*/
class WhenTest {
/**
* when语句
*/
fun isScore(score: Int): String {
return when(score) {
90 -> "优秀"
80 -> "良好"
70 -> "中等"
60 -> "及格"
else -> "不及格"
}
}
/**
* when语句
*/
fun isScore2(score: Int): String {
return when(score) {
in 90..100 -> "优秀"
in 80..89 -> "良好"
in 70..79 -> "中等"
in 60..69 -> "及格"
else -> "不及格"
}
}
/**
* when语句
*/
fun isScore3(score: Int): String {
return when(score) {
90, 100 -> "优秀"
80, 89 -> "良好"
70, 79 -> "中等"
60, 69 -> "及格"
else -> "不及格"
}
}
/**
* when语句
*/
fun isScore4(score: Int): String {
return when(score) {
90, 100 -> "优秀"
80, 89 -> "良好"
70, 79 -> "中等"
60, 69 -> "及格"
else -> {
println("else")
"不及格"
}
}
}
/**
* when语句
*/
fun isScore5(score: Int): String {
return when(score) {
90, 100 -> "优秀"
80, 89 -> "良好"
70, 79 -> "中等"
60, 69 -> "及格"
else -> {
println("else")
"不及格"
}
}
}
/**
* when语句
*/
fun isScore6(score: Int): String {
return when (score) {
90, 100 -> "优秀"
80, 89 -> "良好"
70, 79 -> "中等"
60, 69 -> "及格"
else -> {
println("else")
"不及格"
}
}
}
}
fun main() {
val whenTest = WhenTest()
println(whenTest.isScore(90))
println(whenTest.isScore2(90))
println(whenTest.isScore3(90))
println(whenTest.isScore4(90))
println(whenTest.isScore5(90))
println(whenTest.isScore6(90))
}
for (item in 集合) {
代码块
}
package Controller
/**
* @description:
* @author: shu
* @createDate: 2023/7/31 22:33
* @version: 1.0
*/
class ForTest {
// for循环
fun forTest() {
for (i in 1..10) {
println(i)
}
}
// 数组遍历
fun forTest2() {
val arr = arrayOf(1, 2, 3, 4, 5)
for (i in arr) {
println(i)
}
}
// withIndex
fun forTest3() {
val arr = arrayOf(1, 2, 3, 4, 5)
for ((index, value) in arr.withIndex()) {
println("下标:$index, 值:$value")
}
}
}
fun main() {
val forTest = ForTest()
forTest.forTest()
forTest.forTest2()
forTest.forTest3()
}
while (布尔表达式) {
代码块
}
package Controller
/**
* @description:
* @author: shu
* @createDate: 2023/7/31 22:35
* @version: 1.0
*/
class WhileTest {
/**
* while循环
*/
fun whileTest() {
var i = 1
while (i <= 10) {
println(i)
i++
}
}
/**
* do...while循环
*/
fun doWhileTest() {
var i = 1
do {
println(i)
i++
} while (i <= 10)
}
}
fun main() {
val whileTest = WhileTest()
whileTest.whileTest()
whileTest.doWhileTest()
}
Kotlin 有三种结构化跳转表达式: return 默认从最直接包围它的函数或者匿名函数返回。 break 终止最直接包围它的循环。 continue 继续下一次最直接包围它的循环。 所有这些表达式都可以用作更大表达式的一部分:
val s = person.name ?: return
fun foo() {
listOf(1, 2, 3, 4, 5).forEach {
if (it == 3) return // 非局部直接返回到 foo() 的调用者
print(it)
}
println("this point is unreachable")
}
fun foo() {
listOf(1, 2, 3, 4, 5).forEach lit@{
if (it == 3) return@lit // 局部返回到该 lambda 表达式的调用者,即 forEach 循环
print(it)
}
print(" done with explicit label")
}
fun foo() {
listOf(1, 2, 3, 4, 5).forEach {
if (it == 3) return@forEach // 隐式标签更方便。该 lambda 表达式的隐式标签是 foo
print(it)
}
print(" done with implicit label")
}
fun foo() {
run loop@{
listOf(1, 2, 3, 4, 5).forEach {
if (it == 3) return@loop // 从传入 run 的 lambda 表达式非局部返回
print(it)
}
}
print(" done with nested loop")
}
fun foo() {
listOf(1, 2, 3, 4, 5).forEach(fun(value: Int) {
if (value == 3) return // 局部返回到匿名函数的调用者,即 forEach 循环
print(value)
})
print(" done with anonymous function")
}
break 和 continue 标签 在 Kotlin 中任何表达式都可以用标签(label)来标记。 标签的格式为标识符后跟 @ 符号,例如:abc@、fooBar@都是有效的标签。 要为一个表达式加标签,我们只要在其前加标签即可。
loop@ for (i in 1..100) {
// ……
}
现在,我们可以用标签限制 break 或者 continue:
loop@ for (i in 1..100) {
for (j in 1..100) {
if (……) break@loop
}
}
标签限制的 break 跳转到刚好位于该标签指定的循环后面的执行点。 continue 继续标签指定的循环的下一次迭代。
package Controller
/**
* @description:
* @author: shu
* @createDate: 2023/7/31 22:42
* @version: 1.0
*/
class CatchTest {
// try...catch
fun tryCatchTest() {
try {
val a = 10 / 0
} catch (e: Exception) {
println(e.message)
}
}
}
fun main() {
val catchTest = CatchTest()
catchTest.tryCatchTest()
}
try…catch…finally
package Controller
/**
* @description:
* @author: shu
* @createDate: 2023/7/31 22:42
* @version: 1.0
*/
class CatchTest {
// try...catch
fun tryCatchTest() {
try {
val a = 10 / 0
} catch (e: Exception) {
println(e.message)
}finally {
println("finally")
}
}
}
fun main() {
val catchTest = CatchTest()
catchTest.tryCatchTest()
}
try 是一个表达式,即它可以有一个返回值:
val a: Int? = try { input.toInt() } catch (e: NumberFormatException) { null }
try-表达式的返回值是 try 块中的最后一个表达式或者是(所有)catch 块中的最后一个表达式。 finally 块中的内容不会影响表达式的结果。
在 Kotlin 中任何表达式都可以用标签(label)来标记。标签的格式为标识符后跟@符号,如 abc@、_isOK@都是有效的标签。我们可以用 Label 标签来控制 return、break 或 continue 语句的跳转(jump)行为。
package Controller
/**
* @description:
* @author: shu
* @createDate: 2023/8/2 14:40
* @version: 1.0
*/
class LableTest {
fun test(){
loop@ for (i in 1..100){
for (j in 1..100){
if (j == 50){
break@loop
}
}
}
}
}
fun main() {
val lableTest = LableTest()
lableTest.test()
}
Kotlin 中对应的可空数字类型就相当于 Java 中的装箱数字类型:
val str = "abcd 123"
val i = 10
val s = "i = $i" // 求值结果为 "i = 10"
val s = "abc"
val str = "$s.length is ${s.length}" // 求值结果为 "abc.length is 3"
val text = """
for (c in "foo")
print(c)
"""
/**
* @description:
* @author: shu
* @createDate: 2023/7/31 15:32
* @version: 1.0
*/
class StringTest {
var name:String="Hello World 哈哈红红火火恍恍惚惚!"
fun printInfo(){
println(name)
}
// 基本方法
fun baseMethod(){
// 长度
println("字符串长度:${name.length}")
// 判断是否为空
println("字符串是否为空:${name.isEmpty()}")
// 判断是否为空白
println("字符串是否为空白:${name.isBlank()}")
// 判断不为空
println("字符串是否不为空:${name.isNotEmpty()}")
// 判断不为空白
println("字符串是否不为空白:${name.isNotBlank()}")
// 判断是否包含某个字符
println("字符串是否包含:${name.contains("Hello")}")
// 判断是否包含,忽略大小写
println("字符串是否包含:${name.contains("Hello",true)}")
// 判断是否以指定字符串开头
println("字符串是否以Hello开头:${name.startsWith("Hello")}")
// 判断是否以指定字符串开头,忽略大小写
println("字符串是否以Hello开头:${name.startsWith("Hello",true)}")
// 判断是否以指定字符串结尾
println("字符串是否以World!结尾:${name.endsWith("World!")}")
// 判断是否以指定字符串结尾,忽略大小写
println("字符串是否以World!结尾:${name.endsWith("World!",true)}")
// 截取
println("截取字符串:${name.substring(0,5)}")
println("截取字符串:${name.substring(0 until 5)}")
// 反转
println("反转字符串:${name.reversed()}")
// 替换
println("替换字符串:${name.replace("Hello","你好")}")
// 分割
println("分割字符串:${name.split(" ")}")
// 去除空格
println("去除空格:${name.trim()}")
println("去除左侧空格:${name.trimStart()}")
println("去除右侧空格:${name.trimEnd()}")
// 去除指定字符
println("去除指定字符:${name.trim('H','!')}")
println("去除左侧指定字符:${name.trimStart('H','!')}")
println("去除右侧指定字符:${name.trimEnd('H','!')}")
}
}
fun main() {
val stringTest = StringTest()
stringTest.printInfo()
stringTest.baseMethod()
}
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) |
当初始化一个没有显式指定类型的变量时,编译器会自动推断为足以表示该值的最小类型。 如果不超过 Int 的表示范围,那么类型是 Int。 如果超过了, 那么类型是 Long。 如需显式指定 Long 值,请给该值追加后缀 L。 显式指定类型会触发编译器检测该值是否超出指定类型的表示范围。
对于实数,Kotlin 提供了浮点类型 Float 与 Double 类型,遵循 IEEE 754 标准。 Float 表达 IEEE 754 单精度,而 Double 表达_双精度_。
这两个类型的大小不同,并为两种不同精度的浮点数提供存储:
类型 | 大小(比特数) | 有效数字比特数 | 指数比特数 | 十进制位数 |
---|---|---|---|---|
Float | 32 | 24 | 8 | 6-7 |
Double | 64 | 53 | 11 | 15-16 |
/**
* @description:
* @author: shu
* @createDate: 2023/7/31 15:47
* @version: 1.0
*/
class NumberTest {
// 十进制
var a: Int = 100
// 十六进制
var b: Int = 0x100
// 二进制
var c: Int = 0b100
// Long类型需要加L
var d: Long = 100L
// Float类型需要加f
var e: Float = 100.0f
// Double类型可以不加
var f: Double = 100.0
// Short类型
var g: Short = 100
// Byte类型
var h: Byte = 100
}
fun main(){
var numberTest = NumberTest()
println(numberTest.a)
println(numberTest.b)
println(numberTest.c)
println(numberTest.d)
println(numberTest.e)
println(numberTest.f)
println(numberTest.g)
println(numberTest.h)
}
注意:与一些其他语言不同,Kotlin 中的数字没有隐式拓宽转换。 例如,具有 Double 参数的函数只能对 Double 值调用,而不能对 Float、 Int 或者其他数字值调用
Java 中的面试题?
fun main() {
//sampleStart
val a: Int = 100
val boxedA: Int? = a
val anotherBoxedA: Int? = a
val b: Int = 10000
val boxedB: Int? = b
val anotherBoxedB: Int? = b
println(boxedA === anotherBoxedA) // true
println(boxedB === anotherBoxedB) // false
//sampleEnd
}
由于 JVM 对 -128 到 127 的整数(Integer)应用了内存优化,因此,a 的所有可空引用实际上都是同一对象。但是没有对 b 应用内存优化,所以它们是不同对象。
所有数字类型都支持转换为其他类型
/**
* @description:
* @author: shu
* @createDate: 2023/7/31 15:47
* @version: 1.0
*/
class NumberTest {
// 十进制
var a: Int = 100
// 十六进制
var b: Int = 0x100
// 二进制
var c: Int = 0b100
// Long类型需要加L
var d: Long = 100L
// Float类型需要加f
var e: Float = 100.0f
// Double类型可以不加
var f: Double = 100.0
// Short类型
var g: Short = 100
// Byte类型
var h: Byte = 100
}
fun main(){
var numberTest = NumberTest()
// println(numberTest.a)
// println(numberTest.b)
// println(numberTest.c)
// println(numberTest.d)
// println(numberTest.e)
// println(numberTest.f)
// println(numberTest.g)
// println(numberTest.h)
// 所有数字类型都支持转换为其他类型
println(numberTest.a.toLong())
println(numberTest.a.toFloat())
println(numberTest.a.toDouble())
println(numberTest.a.toShort())
println(numberTest.a.toByte())
}
所有数字类型都支持转换为其他类型:
数字运算
/**
* @description:
* @author: shu
* @createDate: 2023/7/31 15:47
* @version: 1.0
*/
class NumberTest {
// 十进制
var a: Int = 100
// 十六进制
var b: Int = 0x100
// 二进制
var c: Int = 0b100
// Long类型需要加L
var d: Long = 100L
// Float类型需要加f
var e: Float = 100.0f
// Double类型可以不加
var f: Double = 100.0
// Short类型
var g: Short = 100
// Byte类型
var h: Byte = 100
}
fun main(){
var numberTest = NumberTest()
// println(numberTest.a)
// println(numberTest.b)
// println(numberTest.c)
// println(numberTest.d)
// println(numberTest.e)
// println(numberTest.f)
// println(numberTest.g)
// println(numberTest.h)
// 所有数字类型都支持转换为其他类型
println(numberTest.a.toLong())
println(numberTest.a.toFloat())
println(numberTest.a.toDouble())
println(numberTest.a.toShort())
println(numberTest.a.toByte())
// 数字运算
println(numberTest.a + numberTest.b)
println(numberTest.a - numberTest.b)
println(numberTest.a * numberTest.b)
println(numberTest.a / numberTest.b)
println(numberTest.a % numberTest.b)
// 位运算
println(numberTest.a and numberTest.b)
println(numberTest.a or numberTest.b)
println(numberTest.a xor numberTest.b)
println(numberTest.a shl 2)
println(numberTest.a shr 2)
println(numberTest.a ushr 2)
println(numberTest.a.inv())
// 比较运算
println(numberTest.a > numberTest.b)
println(numberTest.a < numberTest.b)
println(numberTest.a >= numberTest.b)
println(numberTest.a <= numberTest.b)
println(numberTest.a == numberTest.b)
println(numberTest.a != numberTest.b)
// 逻辑运算
println(numberTest.a > numberTest.b && numberTest.a < numberTest.b)
println(numberTest.a > numberTest.b || numberTest.a < numberTest.b)
println(!numberTest.a.equals(numberTest.b))
}
字符可以以转义反斜杠 \ 开始。 支持这几个转义序列:
println("Hello\tWorld!")
println("Hello\bWorld!")
println("Hello\nWorld!")
println("Hello\rWorld!")
println("Hello\'World!")
println("Hello\"World!")
println("Hello\\World!")
println("Hello\$World!")
布尔用 Boolean 类型表示,它有两个值:true 和 false。 布尔值的内置运算有: ||——析取(逻辑或) &&——合取(逻辑与) !——否定(逻辑非) || 与 && 都是惰性(短路)的。
val b = true
val c = false
println(b || c)
println(b && c)
println(!b)
数组在 Kotlin 中使用 Array 类来表示,它定义了 get 和 set 函数(按照运算符重载约定这会转变为 [])以及 size 属性,以及一些其他有用的成员函数:
/**
* @description:
* @author: shu
* @createDate: 2023/7/31 16:10
* @version: 1.0
*/
class ArrayTest {
// 数组的创建
var arr1 = arrayOf(1, 2, 3, 4, 5)
var arr2 = arrayOfNulls<Int>(5)
var arr3 = Array(5) { i -> (i * 2) }
// 数组的遍历
fun printArray() {
for (i in arr1) {
println(i)
}
for (i in arr2) {
println(i)
}
for (i in arr3) {
println(i)
}
}
// 原生类型数组
var intArr = intArrayOf(1, 2, 3, 4, 5)
var charArr = charArrayOf('a', 'b', 'c')
var longArr = longArrayOf(1, 2, 3, 4, 5)
var doubleArr = doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0)
var booleanArr = booleanArrayOf(true, false, true)
// 数组的遍历
fun printArray2() {
for (i in intArr) {
println(i)
}
for (i in charArr) {
println(i)
}
for (i in longArr) {
println(i)
}
for (i in doubleArr) {
println(i)
}
for (i in booleanArr) {
println(i)
}
}
}
fun main() {
var arrayTest = ArrayTest()
arrayTest.printArray()
arrayTest.printArray2()
}
Kotlin 提供了一组无符号类型,用来改善对数字溢出的处理。这些类型在 Kotlin/JVM 中不可用。
类型 | 大小(比特数) | 最小值 | 最大值 |
---|---|---|---|
UByte | 8 | 0 | 255 |
UShort | 16 | 0 | 65535 |
UInt | 32 | 0 | 2^32-1 |
ULong | 64 | 0 | 2^64-1 |
无符号类型的字面值分为两类:十进制和十六进制。对于十进制,没有前缀;对于十六进制,前缀是 0x。例如:
val a: UInt = 23u
val b: ULong = 23uL
val c: ULong = 0xCAFEBABEu
无符号类型支持常用的算术运算,以及位运算。请注意,无符号类型不支持有符号类型的减法或者除法。
val a: UInt = 23u
val b: UInt = 22u
val c: UInt = a + b
val d: UInt = a shl 2
无符号类型支持转换为有符号类型,反之亦然。转换时,有符号类型的负数会被转换为大的无符号类型。例如:
val x: Int = -1
val y: Long = x.toULong()
使用 is 操作符或其否定形式 !is 在运行时检测对象是否符合给定类型
/**
* @description: is 类型判断
* @author: shu
* @createDate: 2023/7/31 21:03
* @version: 1.0
*/
class IsTypeTest {
/**
* 判断是否是String类型
*/
fun isString(obj: Any): Boolean {
return obj is String
}
/**
* 判断是否不是Int类型
*/
fun notIsInt(obj: Any): Boolean {
return obj !is Int
}
}
fun main() {
val isTypeTest = IsTypeTest()
println(isTypeTest.isString("abc"))
println(isTypeTest.notIsInt("abc"))
}
智能替换
大多数场景都不需要在 Kotlin 中使用显式转换操作符,因为编译器跟踪不可变值的 is-检测以及显式转换,并在必要时自动插入(安全的)转换
/**
* @description: is 类型判断
* @author: shu
* @createDate: 2023/7/31 21:03
* @version: 1.0
*/
class IsTypeTest {
/**
* 判断是否是String类型
*/
fun isString(obj: Any): Boolean {
return obj is String
}
/**
* 判断是否不是Int类型
*/
fun notIsInt(obj: Any): Boolean {
return obj !is Int
}
/**
* 判断是否是String类型
*/
fun isType(obj: Any) {
when(obj) {
is String -> println("obj is String")
is Int -> println("obj is Int")
is Long -> println("obj is Long")
is Boolean -> println("obj is Boolean")
is Array<*> -> println("obj is Array")
is Char -> println("obj is Char")
is Float -> println("obj is Float")
is Double -> println("obj is Double")
is Short -> println("obj is Short")
is Byte -> println("obj is Byte")
else -> println("obj is not know")
}
}
}
fun main() {
val isTypeTest = IsTypeTest()
// println(isTypeTest.isString("abc"))
// println(isTypeTest.notIsInt("abc"))
isTypeTest.isType("abc")
}
请注意,当编译器能保证变量在检测和使用之间不可改变时,智能转换才有效。 更具体地,智能转换适用于以下情形:
或许 Java 和 Android 开发者早已厌倦了空指针异常(Null Pointer Exception)。因为其在运行时总会在某个意想不到的地方忽然出现,让开发者感到措手不及。
Java
package Controller;
import java.util.Optional;
/**
* @description:
* @author: shu
* @createDate: 2023/8/2 15:01
* @version: 1.0
*/
public class OptionalTest {
public static void main(String[] args) {
Optional<String> optional = Optional.of("hello");
System.out.println(optional.isPresent());
System.out.println(optional.get());
System.out.println(optional.orElse("world"));
optional.ifPresent(s -> System.out.println(s.charAt(0)));
}
}
Kotlin
package Controller
import java.util.*
/**
* @description:
* @author: shu
* @createDate: 2023/8/2 15:01
* @version: 1.0
*/
object OptionalTest {
@JvmStatic
fun main(args: Array<String>) {
// ? 来表达非空
val str: String? = null
println(str?.length)
}
}
package Controller
import java.util.*
/**
* @description:
* @author: shu
* @createDate: 2023/8/2 15:01
* @version: 1.0
*/
object OptionalTest {
@JvmStatic
fun main(args: Array<String>) {
// ? 来表达非空
val str: String? = null
println(str?.length)
// !! 表示非空断言
println(str!!.length)
// ?: 默认值
println(str?.length ?: -1)
}
}
class 类名 {
属性
方法
}
class 类名(参数列表) {
属性
方法
}
/**
* @description:
* @author: shu
* @createDate: 2023/8/1 14:11
* @version: 1.0
*/
class Person @Inject constructor(var name: String, var age: Int) {
init {
println("init")
}
}
class Person constructor(firstName: String) {
init {
println("FirstName is $firstName")
}
}
class 类名 {
constructor(参数列表) {
// 构造函数的函数体
}
}
package Class
/**
* @description:
* @author: shu
* @createDate: 2023/8/1 14:11
* @version: 1.0
*/
class Person (var name: String, var age: Int) {
constructor(name: String) : this(name, 0) {
println("constructor")
}
init {
println("init")
}
}
fun main() {
val person = Person("Alice", 20)
println(person.name)
println(person.age)
println("-----------")
val person1 = Person("Alice01")
println(person1.name)
}
val 对象名 = 类名(参数列表)
抽象类用来表征问题领域的抽象概念。所有编程语言都提供抽象机制。机器语言是对机器的模仿抽象,汇编语言是对机器语言的高层次抽象,高级语言(Fortran、C、BASIC 等)是对汇编的高层次抽象。而我们这里所说的面向对象编程语言是对过程函数的高层次封装。
抽象是相对于具象而言的。例如,设计一个图形编辑软件,问题领域中存在着长方形(Rectangle)、圆形(Circle)、三角形(Triangle)等一些具体概念,它们是具象。但是它们又都属于形状(Shape)这个抽象的概念。
package Class
/**
* @description:
* @author: shu
* @createDate: 2023/8/2 20:46
* @version: 1.0
*/
abstract class Shape {
abstract fun draw()
abstract fun erase()
}
package Class
/**
* @description:
* @author: shu
* @createDate: 2023/8/1 15:16
* @version: 1.0
*/
class Rectangle: Shape() {
override fun draw() {
println("绘制矩形")
}
override fun erase() {
println("擦除矩形")
}
}
fun main() {
val rectangle = Rectangle()
rectangle.draw()
rectangle.erase()
}
package Class
/**
* @description:
* @author: shu
* @createDate: 2023/8/2 20:48
* @version: 1.0
*/
class Circle: Shape() {
override fun draw() {
println("绘制圆形")
}
override fun erase() {
println("擦除圆形")
}
}
fun main() {
val circle = Circle()
circle.draw()
circle.erase()
}
现在我们有了抽象类,但是没有成员。通常,一个类的成员包括属性和函数。抽象类的成员也必须是抽象的,需要使用 abstract 关键字修饰。下面我们声明一个抽象类 Shape,并带有 width、heigth、radius 属性
package Class
/**
* @description:
* @author: shu
* @createDate: 2023/8/2 20:46
* @version: 1.0
*/
abstract class Shape {
abstract var wight: Double
abstract var height: Double
abstract var radius: Double
abstract fun draw()
abstract fun erase()
}
构造函数实现
package Class
/**
* @description:
* @author: shu
* @createDate: 2023/8/1 15:16
* @version: 1.0
*/
class Rectangle(override var wight: Double, override var height: Double, override var radius: Double) : Shape() {
override fun draw() {
println("绘制矩形")
}
override fun erase() {
println("擦除矩形")
}
}
fun main() {
val rectangle = Rectangle(1.0, 2.0, 3.0)
rectangle.draw()
rectangle.erase()
}
package Class
/**
* @description:
* @author: shu
* @createDate: 2023/8/2 20:48
* @version: 1.0
*/
class Circle(override var wight: Double, override var height: Double, override var radius: Double) : Shape() {
override fun draw() {
println("绘制圆形")
}
override fun erase() {
println("擦除圆形")
}
}
fun main() {
val circle = Circle(1.0, 2.0, 3.0)
circle.draw()
circle.erase()
}
当子类继承了某个类之后,便可以使用父类中的成员变量,但并不是完全继承父类的所有成员变量。具体的原则如下:
接口是一种比抽象类更加抽象的“类”。接口本身代表的是一种“类型”的概念。但在语法层面,接口本身不是类,不能实例化接口,只能实例化它的实现类。
interface 接口名 {
属性
方法
}
接口是没有构造函数的。我们使用冒号“:”语法来实现一个接口,如果有多个接口,用“,”逗号隔开:
class 类名 : 接口名 {
属性
方法
}
package Interface
/**
* @description: 接口是指具有相同属性和方法的对象的集合,它定义了该集合中每个对象所共有的属性和方法。对象是接口的实例。
* Kotlin 的接口可以既包含抽象方法的声明也包含实现。与抽象类不同的是,接口无法保存状态。它可以有属性但必须声明为抽象或提供访问器实现。
* @createDate: 2023/8/1 15:31
* @version: 1.0
*/
interface Person {
/**
* 定义一个方法
*/
fun eat(name: String)
}
class Student : Person {
/**
* 实现接口中的方法
*/
override fun eat(name: String) {
println("$name is eating. ")
}
}
fun main(args: Array<String>) {
val student = Student()
student.eat("shu")
}
interface 接口名 {
var/val 属性名: 属性类型
}
package Interface
/**
* @description: 接口是指具有相同属性和方法的对象的集合,它定义了该集合中每个对象所共有的属性和方法。对象是接口的实例。
* Kotlin 的接口可以既包含抽象方法的声明也包含实现。与抽象类不同的是,接口无法保存状态。它可以有属性但必须声明为抽象或提供访问器实现。
* @createDate: 2023/8/1 15:31
* @version: 1.0
*/
interface Person {
/**
* 定义一个属性
*/
var name: String
/**
* 定义一个方法
*/
fun eat(name: String)
}
class Student : Person {
/**
* 实现接口中的属性
*/
override var name: String = "shu"
/**
* 实现接口中的方法
*/
override fun eat(name: String) {
println("$name is eating. ")
}
}
fun main(args: Array<String>) {
val student = Student()
student.eat("shu")
println(student.name)
}
interface 子接口名 : 父接口名 {
属性
方法
}
package Interface
/**
* @createDate: 2023/8/1 15:31
* @version: 1.0
*/
interface Person {
/**
* 定义一个属性
*/
var name: String
/**
* 定义一个方法
*/
fun eat(name: String)
}
interface Student : Person {
/**
* 定义一个属性
*/
var age: Int
/**
* 定义一个方法
*/
fun study(name: String)
}
class StudentImpl : Student {
/**
* 实现接口中的属性
*/
override var name: String = "shu"
/**
* 实现接口中的属性
*/
override var age: Int = 20
/**
* 实现接口中的方法
*/
override fun eat(name: String) {
println("$name is eating. ")
}
/**
* 实现接口中的方法
*/
override fun study(name: String) {
println("$name is studying. ")
}
}
fun main(args: Array<String>) {
val student = StudentImpl()
student.eat("shu")
println(student.name)
student.study("shu")
println(student.age)
}
fun interface KRunnable {
fun invoke()
}
fun interface 函数式接口名 {
fun 方法名(参数列表): 返回值类型
}
package Interface
/**
* @description:
* @createDate: 2023/8/1 15:31
* @version: 1.0
*/
fun interface KRunnable {
fun invoke()
}
class KThread : KRunnable {
override fun invoke() {
println("KThread is running. ")
}
}
fun main(args: Array<String>) {
val kThread = KThread()
kThread.invoke()
}
单例模式是一种常用的软件设计模式。例如,Spring 中的 Bean 默认就是单例。通过单例模式可以保证系统中一个类只有一个实例。即一个类只有一个对象实例。
Kotlin 中没有静态属性和方法,但是可以使用关键字 object 声明一个 object 单例对象:
package Class
/**
* @description:
* @author: shu
* @createDate: 2023/8/2 21:03
* @version: 1.0
*/
object User {
var name: String = "shu"
var age: Int = 18
fun eat() {
println("eat")
}
}
fun main() {
println(User.name)
println(User.age)
User.eat()
}
Kotlin 中还提供了伴生对象,用 companion object 关键字声明,一个类只能有一个伴生对象。
package Class
/**
* @description:
* @author: shu
* @createDate: 2023/8/1 15:02
* @version: 1.0
*/
open class Person {
open var name: String = "shu"
/**
* 定义一个方法
*/
open fun eat(name: String) {
println("$name is eating. ")
}
companion object {
@JvmStatic
fun main(args: Array<String>) {
val person = Person()
person.eat("shu")
}
}
}
数据类就是只存储数据,不包含操作行为的类。Kotlin 中的数据类可以为我们节省大量的样板代码(Java 中强制我们要去写一堆 getter、setter 代码,而实际上这些方法都是“不言自明”的),这样最终的代码更易于理解,便于维护。
数据类有如下限制:
格式:
data class LoginUser(val username: String, val password: String)
package Class
/**
* @description:
* @author: shu
* @createDate: 2023/8/2 21:14
* @version: 1.0
*/
data class LoginUser(val username: String, val password: String)
fun main(){
val loginUser = LoginUser("shu", "123456")
println(loginUser)
}
Kotlin 标准库提供了 Pair 和 Triple 数据类,分别表示二元组和三元组对象。它们的定义分别如下:
public data class Pair<out A, out B>(public val first: A, public val second: B) : Serializable {
override fun toString(): String = "($first, $second)"
}
public data class Triple<out A, out B, out C>(
public val first: A,
public val second: B,
public val third: C
) : Serializable {
override fun toString(): String = "($first, $second, $third)"
}
package Class
/**
* @description:
* @author: shu
* @createDate: 2023/8/2 21:14
* @version: 1.0
*/
data class LoginUser(val username: String, val password: String)
fun main(){
val loginUser = LoginUser("shu", "123456")
println(loginUser)
// 二元
Pair("shu", "123456").let {
println(it)
}
// 三元
Triple("shu", "123456", "123456").let {
println(it)
}
}
Kotlin 中使用 enum class 关键字来声明一个枚举类。
相比于字符串常量,使用枚举能够实现类型安全。枚举类有两个内置的属性:name,ordinal
package Class
/**
* @description:
* @author: shu
* @createDate: 2023/8/3 9:31
* @version: 1.0
*/
enum class Color {
RED, GREEN, BLUE, ORANGE, YELLOW, INDIGO, VIOLET
}
fun main() {
println(Color.RED)
println(Color.GREEN)
println(Color.BLUE)
println(Color.ORANGE)
println(Color.YELLOW)
println(Color.INDIGO)
println(Color.VIOLET)
}
Kotlin 中,类可以嵌套。一个类可以嵌套在其他类中,而且可以嵌套多层。
如果一个类 Inner 想要访问外部类 Outer 中的成员,可以在这个类前面添加修饰符 inner,内部类会带有一个对外部类的对象引用。
package Class
/**
* @description:
* @author: shu
* @createDate: 2023/8/3 9:34
* @version: 1.0
*/
class NestClass {
inner class InnerClass {
fun getOuterReference(): NestClass = this@NestClass
}
class NestedClass {
fun getOuterReference(): NestClass = NestClass()
}
}
fun main() {
val nestClass = NestClass()
val innerClass = nestClass.InnerClass()
val nestedClass = NestClass.NestedClass()
println(innerClass.getOuterReference())
println(nestedClass.getOuterReference())
}
匿名内部类就是没有名字的内部类。匿名内部类也可以访问外部类的变量。
package Class
/**
* @description:
* @author: shu
* @createDate: 2023/8/3 9:37
* @version: 1.0
*/
object AnonymousClass {
@JvmStatic
fun main(args: Array<String>) {
// 匿名类
Thread { println("匿名类") }.start()
// lambda表达式
Thread { println("lambda表达式") }.start()
}
}
函数式编程是关于不变性和函数组合的编程范式。函数式编程有如下特征。
package Fun
/**
* @description:
* @author: shu
* @createDate: 2023/8/3 9:44
* @version: 1.0
*/
class FunTest {
fun Test(){
println("""fun main(){""")
}
}
fun main(){
val funTest = FunTest()
funTest.Test()
println("""}""")
}
学过 Java 的都用该知道
package Fun
/**
* @description:
* @author: shu
* @createDate: 2023/8/3 9:46
* @version: 1.0
*/
class Lambda {
val sum = { x: Int, y: Int -> x + y }
val sum2: (Int, Int) -> Int = { x, y -> x + y }
}
fun main() {
val lambda = Lambda()
println(lambda.sum(1, 2))
println(lambda.sum2(1, 2))
}
本节我们介绍 Kotlin 中的 run()、apply()、let()、also()和 with()这 5 个特殊的函数。
package Fun
import Class.User.age
import Class.User.eat
import Class.User.name
/**
* @description:
* @author: shu
* @createDate: 2023/8/3 10:11
* @version: 1.0
*/
class PersonDemo(var name: String, var age: Int) {
fun eat() {
println("吃柠檬")
}
fun work(hour: Int): Int {
println("work $hour hour,earn ¥${hour * 60}")
return hour * 60
}
}
fun main() {
testWith()
testRun()
testApply()
testAlso()
}
// 测试with函数
// with函数是一个顶层函数,它的定义如下:
// public inline fun with(receiver: T, block: T.() -> R): R = receiver.block()
// with函数的作用是将某对象作为函数的参数,在函数块内可以通过this指代该对象。返回值为函数块的最后一行或指定return表达式。
// with()函数是一个内联函数,它把传入的对象作为接受者,在该函数内可以使用this指代该对象来访问其公有的属性和方法。
// 该函数的返回值为函数块最后一行或指定的return表示式。
fun testWith() {
val person = PersonDemo("张三", 18)
val result = with(person) {
println("name:$name,age:$age")
eat()
work(8)
}
// 最后一行是返回值
println(result)
}
// 测试run函数
// run函数是一个扩展函数,它的定义如下:
// public inline fun T.run(block: T.() -> R): R = block()
// run函数的作用是将某对象作为函数的参数,在函数块内可以通过this指代该对象。返回值为函数块的最后一行或指定return表达式。
// run()函数是with()和let()函数的结合体,它可以像with()函数一样直接在函数块中使用this指代该对象,也可以像let()函数一样为对象做统一的判空处理。
fun testRun() {
val person = PersonDemo("张三", 18)
person.run {
println("name:$name,age:$age")
eat()
work(8)
}
}
// 测试apply函数
// apply函数是一个扩展函数,它的定义如下:
// public inline fun T.apply(block: T.() -> Unit): T { block(); return this }
// apply函数的作用是将某对象作为函数的参数,在函数块内可以通过this指代该对象。返回值为该对象自己。
// apply()函数和run()函数相似,不同的是,run()函数是以闭包形式返回最后一行代码的值,而apply()函数返回的是传入的对象本身。
fun testApply() {
val person = PersonDemo("张三", 18)
val result=person.apply {
println("name:$name,age:$age")
eat()
work(8)
}
println(result)
}
// 测试also函数
// also函数是一个扩展函数,它的定义如下:
// public inline fun T.also(block: (T) -> Unit): T { block(this); return this }
// also()函数和apply()函数相似,不同的是,also()函数在函数块中使用it指代该对象,而apply()函数在函数块中使用this指代该对象。
fun testAlso() {
val person = PersonDemo("张三", 18)
val result= person.also {
println("name:${it.name},age:${it.age}")
it.eat()
it.work(8)
}
println(result)
}
// 测试let函数
// let函数是一个扩展函数,它的定义如下:
// public inline fun T.let(block: (T) -> R): R = block(this)
// let()函数是一个扩展对象函数,它可以对被扩展的对象做统一的判空处理,在函数块内使用it来指代该对象,可以访问对象的公有属性和方法。let()函数的返回值和with()函数一样,为函数块最后一行或指定的return表示式
fun testLet() {
val person = PersonDemo("张三", 18)
val result = person.let {
println("name:${it.name},age:${it.age}")
it.eat()
it.work(8)
}
println(result)
}
fun 类名.方法名(参数列表): 返回值类型 {
方法体
}
package Fun
/**
* @description: 扩展函数是指在不改变原类的基础上,为类添加新的函数。
* @createDate: 2023/8/3 10:11
* @version: 1.0
*/
fun String.addExt(): String {
return "shu"
}
fun main() {
println("".addExt())
}
val 类名.属性名: 属性类型
get() = 属性的get方法
set(value) = 属性的set方法
package Fun
/**
* @description: 扩展属性是指在不改变原类的基础上,为类添加新的属性。
* @createDate: 2023/8/3 10:11
* @version: 1.0
*/
val String.addExt: String
get() = "shu"
fun main() {
println("".addExt)
}
在 Java 类库中有一套相当完整的容器集合类来持有对象。Kotlin 没有去重复造轮子(Scala 则是自己实现了一套集合类框架),而是在 Java 类库的基础上进行了改造和扩展,引入了不可变集合类,同时扩展了大量方便实用的功能,这些功能的 API 都在 kotlin.collections 包下面。
集合类存放的都是对象的引用,而非对象本身,我们通常说的集合中的对象指的是集合中对象的引用(reference)。Kotlin 的集合类分为:可变集合类(Mutable)与不可变集合类(Immutable)。
集合类主要有 3 种:List(列表)、Set(集)和Map(映射),List 容器中的元素以线性方式存储,集合中可以存放重复对象。列表中的元素是有序地排列。
List 列表分为只读不可变的 List 和可变 MutableList(可写入、删除数据)
Set 集也分为不可变 Set 和可变 MutableSet(可写入、删除数据)
Kotlin 中的 Map 与 List、Set 一样,Map 也分为只读 Map 和可变 MutableMap(可写入、删除数据)。Map 没有继承于 Collection 接口
Kotlin 中分别使用 listOf()、setOf()、mapOf()函数创建不可变的 List 列表容器、Set 集容器、Map 映射容器;使用 mutableListOf()、mutableSetOf()、mutableMapOf()函数来创建可变的 MutableList 列表容器、MutableSet 集容器、MutableMap 映射容器
package Fun
/**
* @description:
* @author: shu
* @createDate: 2023/8/3 21:04
* @version: 1.0
*/
class ListTest {
// 1. 创建一个不可变集合
val list = listOf("apple", "banana", "orange", "pear", "grape")
// 2. 创建一个可变集合
val mutableList = mutableListOf("apple", "banana", "orange", "pear", "grape")
// 3. 创建一个空集合
val emptyList = emptyList<String>()
// 4. 创建一个单元素集合
}
etOf()、mapOf()分析同理,下面我们来分析集合的方法
fun traverseList() {
// 1.1 for循环遍历
for (fruit in list) {
println(fruit)
}
// 1.2 forEach遍历
list.forEach { fruit ->
println(fruit)
}
// 1.3 forEachIndexed遍历
list.forEachIndexed { index, fruit ->
println("$index : $fruit")
}
// 1.4 迭代器遍历
val iterator = list.iterator()
while (iterator.hasNext()) {
println(iterator.next())
}
}
// 2. 集合转换
fun transformList() {
// 2.1 map转换
val newList = list.map { fruit ->
fruit.toUpperCase()
}
println(newList)
// 2.2 mapIndexed转换
val newList2 = list.mapIndexed { index, fruit ->
"$index : $fruit"
}
println(newList2)
// 2.3 mapNotNull转换
val newList3 = list.mapNotNull { fruit ->
if (fruit.length > 5) {
fruit.toUpperCase()
} else {
null
}
}
println(newList3)
// 2.4 flatMap转换
val newList4 = list.flatMap { fruit ->
fruit.toList()
}
println(newList4)
// 2.5 flatMapIndexed转换
val newList5 = list.flatMapIndexed { index, fruit ->
"$index : $fruit".toList()
}
println(newList5)
// 2.6 zip转换
val newList6 = list.zip(listOf("苹果", "香蕉", "橘子", "梨", "葡萄"))
println(newList6)
// 2.7 zipWithNext转换
val newList7 = list.zipWithNext()
println(newList7)
}
// 7.6 过滤函数
fun Filter(){
// 7.6.1 过滤函数
list.filter { fruit ->
fruit.length > 5
}.forEach { fruit ->
println(fruit)
}
// 7.6.2 过滤函数
list.filterIndexed { index, fruit ->
index > 2 && fruit.length > 5
}.forEach { fruit ->
println(fruit)
}
list.filterNot { fruit ->
fruit.length > 5
}.forEach { fruit ->
println(fruit)
}
list.filterNotNull().forEach { fruit ->
println(fruit)
}
list.filterIndexedTo(mutableList) { index, fruit ->
index > 2 && fruit.length > 5
}
list.filterNotTo(mutableList) { fruit ->
fruit.length > 5
}
list.filterNotNullTo(mutableList)
}
// 排序函数
fun Sort(){
// 7.7.1 排序函数
list.sorted().forEach { fruit ->
println(fruit)
}
// 7.7.2 排序函数
list.sortedBy { fruit ->
fruit.length
}.forEach { fruit ->
println(fruit)
}
// 7.7.3 排序函数
list.sortedDescending().forEach { fruit ->
println(fruit)
}
// 7.7.4 排序函数
list.sortedByDescending { fruit ->
fruit.length
}.forEach { fruit ->
println(fruit)
}
// 7.7.5 排序函数
list.sortedWith(compareBy { fruit ->
fruit.length
}).forEach { fruit ->
println(fruit)
}
// 7.7.6 排序函数
list.sortedWith(compareByDescending { fruit ->
fruit.length
}).forEach { fruit ->
println(fruit)
}
// 7.7.7 排序函数
list.reversed().forEach { fruit ->
println(fruit)
}
// 7.7.8 排序函数
list.asReversed().forEach { fruit ->
println(fruit)
}
}
// 去重
fun distinct() {
list.distinct().forEach { fruit ->
println(fruit)
}
}
其他参考:http://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/index.html。
class 类名<泛型名1, 泛型名2, ...> {
// 类体
}
package Fun
/**
* @description: 泛型是指在定义类、接口或方法时,不预先指定具体的类型,而在使用时再指定具体类型的一种特性。
* @createDate: 2023/8/3 21:04
* @version: 1.0
*/
class Generic<T>(t: T) {
var value = t
}
fun main() {
val generic = Generic("shu")
println(generic.value)
}
class 类名<泛型名1, 泛型名2, ...> {
// 类体
}
package Fun
/**
* @description: 泛型是指在定义类、接口或方法时,不预先指定具体的类型,而在使用时再指定具体类型的一种特性。
* @createDate: 2023/8/3 21:04
* @version: 1.0
*/
class Generic<T>(t: T) {
var value = t
fun getValue(): T {
return value
}
fun setValue(value: T) {
this.value = value
}
}
fun main() {
val generic = Generic("shu")
println(generic.value)
generic.setValue("shu2")
println(generic.value)
}
fun 函数名<泛型名1, 泛型名2, ...>(参数列表): 返回值类型 {
// 函数体
}
package Fun
/**
* @description: 泛型是指在定义类、接口或方法时,不预先指定具体的类型,而在使用时再指定具体类型的一种特性。
* @createDate: 2023/8/3 21:04
* @version: 1.0
*/
class Generic<T>(t: T) {
var value = t
fun getValue(): T {
return value
}
fun setValue(value: T) {
this.value = value
}
}
fun <T> getValue(value: T): T {
return value
}
fun main() {
val generic = Generic("shu")
println(generic.value)
generic.setValue("shu2")
println(generic.value)
println(getValue("shu"))
}
fun <T : 上限> 函数名(参数列表): 返回值类型 {
// 函数体
}
package Fun
/**
* @description: 泛型是指在定义类、接口或方法时,不预先指定具体的类型,而在使用时再指定具体类型的一种特性。
* @createDate: 2023/8/3 21:04
* @version: 1.0
*/
class Generic<T>(t: T) {
var value = t
fun getValue(): T {
return value
}
fun setValue(value: T) {
this.value = value
}
}
fun <T : Number> getValue(value: T): T {
return value
}
fun main() {
val generic = Generic("shu")
println(generic.value)
generic.setValue("shu2")
println(generic.value)
println(getValue("shu"))
}
而 Kotlin 抛弃了这个通配符,直接实现了前面所讲的 PECS 的规则。Kotlin 中引入了投射类型 out T 代表生产者对象,投射类型 in T 代表消费者对象,使用投射类型(projected type)out T 和 in T 来实现与类型通配符同样的功能。
package Fun
/**
* @description: 泛型是指在定义类、接口或方法时,不预先指定具体的类型,而在使用时再指定具体类型的一种特性。
* @createDate: 2023/8/3 21:04
* @version: 1.0
*/
class Generic<out T>(t: T) {
var value = t
fun getValue(): T {
return value
}
}
fun main() {
val generic = Generic("shu")
println(generic.value)
println(generic.getValue())
}
package Fun
/**
* @description: 泛型是指在定义类、接口或方法时,不预先指定具体的类型,而在使用时再指定具体类型的一种特性。
* @createDate: 2023/8/3 21:04
* @version: 1.0
*/
class Generic<in T>(t: T) {
var value = t
fun setValue(value: T) {
this.value = value
}
}
fun main() {
val generic = Generic("shu")
println(generic.value)
generic.setValue("shu2")
println(generic.value)
}
在 Kotlin 中,我们把只能保证读取数据时类型安全的对象叫做生产者,用 out T 标记;把只能保证写入数据安全时类型安全的对象叫做消费者,用 in T 标记。可以这么记:out T 等价于? extends T;in T 等价于? super T。
// 读取文件
val file = File("文件路径")
val bufferedReader = BufferedReader(FileReader(file))
val text = bufferedReader.readText()
bufferedReader.close()
// 写入文件
val file = File("文件路径")
val bufferedWriter = BufferedWriter(FileWriter(file))
bufferedWriter.write("写入的内容")
bufferedWriter.close()
package IO
import java.io.File
/**
* @description:
* @author: shu
* @createDate: 2023/8/4 9:19
* @version: 1.0
*/
class FileTest {
// 读取文件 :readText readLines readBytes bufferedReader
// 1: readText 读取文件内容
// 2: readLines 读取文件内容,返回List
// 3: readBytes 读取文件内容,返回ByteArray
// 4: bufferedReader 读取文件内容,返回BufferedReader
fun readFile() {
val file = File("D:\\config.json")
println(file.readText())
println(file.readLines())
println(file.readBytes())
println(file.bufferedReader().readLine())
}
// 写入文件: writeText appendText appendBytes bufferedReader
fun writeFile() {
val file = File("D:\\config01.json")
file.writeText("hello world")
file.appendText("hello world", Charsets.UTF_8) // 追加内容
file.appendBytes("hello world".toByteArray())
file.bufferedReader().readLine()
}
// 读取文件夹
fun readDir() {
val file = File("D:\\")
file.walk().forEach {
println(it)
}
}
// 创建文件夹
fun createDir() {
val file = File("D:\\test")
file.mkdir()
}
// 删除文件夹
fun deleteDir() {
val file = File("D:\\test")
file.delete()
}
// 重命名文件夹
fun renameDir() {
val file = File("D:\\test")
file.renameTo(File("D:\\test01"))
}
// 递归复制
fun copyDir() {
val file = File("D:\\test")
file.copyRecursively(File("D:\\test01"))
}
// 递归删除
fun deleteDirRecursively() {
val file = File("D:\\test")
file.deleteRecursively()
}
// 文件是否存在
fun isExist() {
val file = File("D:\\test")
file.exists()
}
// 文件是否可读
fun isReadable() {
val file = File("D:\\test")
file.canRead()
}
// 文件是否可写
fun isWritable() {
val file = File("D:\\test")
file.canWrite()
}
// 文件是否可执行
fun isExecutable() {
val file = File("D:\\test")
file.canExecute()
}
// 文件大小
fun fileSize() {
val file = File("D:\\test")
file.length()
}
// 文件最后修改时间
fun fileLastModified() {
val file = File("D:\\test")
file.lastModified()
}
// 文件名
fun fileName() {
val file = File("D:\\test")
file.name
}
// 文件路径
fun filePath() {
val file = File("D:\\test")
file.path
}
// 文件绝对路径
fun fileAbsolutePath() {
val file = File("D:\\test")
file.absolutePath
}
// 文件父目录
fun fileParent() {
val file = File("D:\\test")
file.parent
}
}
fun main() {
// FileTest().readFile()
// FileTest().writeFile()
FileTest().readDir()
}
val url = URL("https://www.baidu.com")
val bufferedReader = BufferedReader(InputStreamReader(url.openStream()))
val text = bufferedReader.readText()
bufferedReader.close()
package IO
import java.io.File
import java.net.URL
/**
* @description:
* @author: shu
* @createDate: 2023/8/4 9:35
* @version: 1.0
*/
class NetWorkIo {
// 网络IO
fun NetWorkIoTest(URL: String) {
val url = URL(URL)
val connection = url.openConnection()
val stream = connection.getInputStream()
val text = stream.bufferedReader().readText()
println(text)
// 写入文件中
val file = File("D:\\test.html")
file.writeText(text)
}
// 图片下载
fun downloadImage(URL: String) {
val url = URL(URL)
val connection = url.openConnection()
val stream = connection.getInputStream()
val file = File("D:\\test.jpg")
file.writeBytes(stream.readBytes())
}
}
fun main() {
val netWorkIo = NetWorkIo()
netWorkIo.NetWorkIoTest("https://www.baidu.com")
netWorkIo.downloadImage("https://www.baidu.com/img/bd_logo1.png")
}
val regex = Regex("正则表达式")
val matchResult = regex.find("字符串")
package IO
/**
* @description:
* @author: shu
* @createDate: 2023/8/4 9:40
* @version: 1.0
*/
class RegexTest {
// 正则表达式
fun regexTest() {
val regex = Regex("[0-9]+")
val matchResult = regex.find("hello1234567world")
println(matchResult?.value)
val matchResults = regex.findAll("hello1234567world")
matchResults.forEach {
println(it.value)
}
println(regex.replace("hello1234567world", "world"))
println(regex.replaceFirst("hello1234567world", "world"))
}
}
fun main() {
val regexTest = RegexTest()
regexTest.regexTest()
}
// 创建线程
val thread = Thread {
// 线程体
}
// 启动线程
thread.start()
package Thread
/**
* @description:
* @author: shu
* @createDate: 2023/8/4 9:42
* @version: 1.0
*/
class Thread {
// 创建线程
fun createThread() {
val thread = Thread {
println("hello world")
}
thread.start()
}
// Runnable
fun runnable() {
val runnable = Runnable {
println("hello world")
}
val thread = Thread(runnable)
thread.start()
}
// 同步方法
@Synchronized fun synchronizedTest() {
val thread = Thread()
println("hello world")
}
// 可变字段
@Volatile var flag = false
}
fun main() {
val thread = Thread()
thread.createThread()
thread.runnable()
}
说明:这里的语法格式是使用 lambda 表达式创建线程,也可以使用 Runnable 接口创建线程。