Kotlin開發springboot項目(二)
中文學習網站:
https://www.kotlincn.net/
研究一下kotlin的demo:
https://github.com/JetBrains/kotlin-examples
Kotlin 文件以 .kt 為后綴。
包聲明
kotlin源文件不需要相匹配的目錄和包,源文件可以放在任何文件目錄。
如果沒有指定包,默認為 default 包。
package basic.kotlin.manager.beijing /** * 定義類 */ class 總經理(var 姓: String) { override fun toString(): String { return "${姓}經理" } }
package basic.kotlin.manager.beijing import basic.kotlin.manager.beijing.總經理 as 茶水大王 // 起一個別名 /** * 包必須聲明在非注釋的第一行 */ fun main(args: Array<String>) { val manager: 茶水大王 = 茶水大王("張") println(manager) }
默認導入
有多個包會默認導入到每個 Kotlin 文件中: kotlin.* kotlin.annotation.* kotlin.collections.* kotlin.comparisons.* kotlin.io.* kotlin.ranges.* kotlin.sequences.* kotlin.text.*
基本數據類型:
定義常量與變量
可變變量定義:var 關鍵字
var <標識符> : <類型> = <初始化值>
不可變變量定義:val 關鍵字,只能賦值一次的變量(類似Java中final修飾的變量)
val <標識符> : <類型> = <初始化值>
package basic.kotlin
/**
* 基本數據類型
* 變量名稱:變量類型=變量值
*/
val aBoolean: Boolean = true
val anotherBoolean: Boolean = false
val anInt: Int = 8
val anotherInt: Int = 0xFF
val moreInt: Int = 0b00000011
val maxInt: Int = Int.MAX_VALUE
val minInt: Int = Int.MIN_VALUE
val aLong: Long = 12368172397127391
val another: Long = 123
val maxLong: Long = Long.MAX_VALUE
val minLong: Long = Long.MIN_VALUE
val aFloat: Float = 2.0F
val anotherFloat: Float = 1E3f
val maxFloat: Float = Float.MAX_VALUE
val minFloat: Float = -Float.MAX_VALUE
val aDouble: Double = 3.0
val anotherDouble: Double = 3.1415926
val maxDouble: Double= Double.MAX_VALUE
val minDouble: Double= -Double.MAX_VALUE
val aShort: Short = 127
val maxShort: Short = Short.MAX_VALUE
val minShort: Short = Short.MIN_VALUE
val aByte:Byte=127
val maxByte: Byte = Byte.MAX_VALUE
val minByte: Byte = Byte.MIN_VALUE
val aChar: Char = '0'
val bChar: Char = '中'
val cChar: Char = '\u56fd'
val dChar: Char = '\u000f'
fun main(args: Array<String>) {
println(anotherInt)
println(moreInt)
println(maxInt)
println(Math.pow(2.0, 31.0) - 1)
println(minInt)
println( - Math.pow(2.0, 31.0))
println(maxLong)
println(Math.pow(2.0, 63.0) - 1)
println(minLong)
println(- Math.pow(2.0, 63.0))
println(aFloat)
println(anotherFloat)
println(maxFloat)
println(minFloat)
println(maxDouble)
println(minDouble)
println(maxShort)
println(minShort)
println(aByte)
println(maxByte)
println(minByte)
println(aChar)
println(bChar)
println("Unicode:"+cChar) // 需要轉義才能打印
println("Unicode:"+dChar) // 需要轉義才能打印
}
Range區間
package basic.kotlin
/**
* Range 區間
*/
val range: IntRange = 0..1024 // [0, 1024] 閉區間
val range_exclusive: IntRange = 0 until 1024 // [0, 1024) = [0, 1023] 開區間
val emptyRange: IntRange = 0..-1
fun main(args: Array<String>) {
println(emptyRange.isEmpty()) // 是否為空
println(range.contains(50)) // 是否包含
println(50 in range) // 是否在這個區間
for(i in range_exclusive){ // 循環遍歷
print("$i, ")
}
}
kotlin不支持隱式轉換
package basic.kotlin
/**
* 隱式轉換 與 字符串類型
*/
val aInt:Int= 6
val bLong:Long= aInt.toLong() // int整形轉換為long類型需要顯示轉換,在kotlin中不支持隱式轉換
val string: String = "HelloWorld"
val fromChars: String = String(charArrayOf('H','e','l','l','o','W','o','r','l','d'))
fun main(args: Array<String>) {
println(bLong)
println(string == fromChars) // 雙等號 比較內容 相當於java中的equals
println(string === fromChars) // 三等號 比較引用 相當於java 中比較的引用的地址
println("接下來我們要輸出:" + string)
val arg1: Int = 0
val arg2: Int = 1
println("" + arg1 + " + " + arg2 + " = " + (arg1 + arg2)) // java傳統方式進行字符串拼接
println("$arg1 + $arg2 = ${arg1 + arg2}") // 字符串模板進行字符拼接
//Hello "Trump"
val sayHello : String = "Hello \"Trump\"" // 雙引號轉義
println(sayHello)
//salary
val salary: Int = 1000
//$salary
println("$$salary")
println("\$salary")
// 三個雙引號的字符串原樣輸出,在這種字符串模板拼接時,\ 進行轉義時不起作用
val rawString: String = """
\t
\n
$salary
\$salary
$ salary
"""
println(rawString)
println(rawString.length)
}
kotlin中Any是所有類的父類
package com.basic.kotlin
/**
* 對象繼承關系
*/
// 類的定義方式一:
class 妹子(性格: String, 長相: String, 聲音: String): person(性格, 長相, 聲音)
// 類的定義方式二:
class 帥哥(性格: String, 長相: String, 聲音: String): person(性格, 長相, 聲音){
fun say(){
println("我最帥")
}
}
class 大叔(性格: String, 長相: String, 聲音: String): person(性格, 長相, 聲音){
init{
println("我有房、有車、有存款,我在父類的init方法后運行,在自己的實例每次創建被new時先運行")
}
}
open class person(var 性格: String, var 長相: String, var 聲音: String){
init {
println("new 了一個${this.javaClass.simpleName}, ta性格:$性格, 長相:$長相, 聲音:$聲音")
}
}
fun main(args: Array<String>) {
val girl: 妹子 = 妹子("溫柔", "甜美", "動人")
println(girl is person)
val boy: 帥哥 = 帥哥("彪悍", "帥氣", "渾厚")
boy.say()
val uncle: 大叔 = 大叔("穩重", "成熟", "洪亮")
}
空類型安全
package basic.kotlin
/**
* 空值安全
* 安全的kotlin寫法
*/
fun getName(): String?{ // ? 表示返回值的String類型允許為null
return null
}
fun main(args: Array<String>) {
val str: String? = null //值允許為空
println(str?.length) //值為空直接返回null
val value: String? = "HelloWorld"
println(value!!.length) // 已經明確知道不為空,!! 告訴編譯器,我知道是不為空了,你編譯吧
val name: String = getName() ?: return // ? 表示允許為null 為空直接返回,下邊的打印語句不會執行了
println(name.length)
}
智能類型轉換
定義一個父類
/** * 父類 */ public class Parent { }
定義一個子類
/** * 子類繼承父類 */ public class Child extends Parent { public String getName(){ return "Child"; } }
類型轉換
package basic.kotlin
/**
* 智能識別類型轉換
* 安全的kotlin寫法
*/
fun main(args: Array<String>) {
val p: Parent = Parent()
val c: Parent = Child()
if (c is Child) // 類型相等,就可以執行方法體的內容
println(c.name)
val child: Child? = p as? Child // 轉換失敗不讓其拋出異常,返回個null ,不帶?就會和java原生語法一樣拋出異常
println(child)
val string: String? = "Hello"
if(string != null)
println(string.length) // 智能甄別 ,前邊判斷了,后邊不用判斷了
}
數組
package basic.kotlin
import basic.kotlin.manager.beijing.總經理 as m1
/**
* 數組
*/
val arrayOfInt: IntArray = intArrayOf(1,3,5,7)
val arrayOfChar: CharArray = charArrayOf('H', 'e','l','l','o','W','o','r','l','d')
val arrayOfString: Array<String> = arrayOf("我", "是", "碼農")
val arrayOf經理: Array<m1> = arrayOf(m1("張"),m1("李"))
fun main(args: Array<String>) {
println(arrayOfInt.size)
for(int in arrayOfInt){
print("$int \t")
}
println()
println(arrayOfString.joinToString(""))
println(arrayOf經理[1])
arrayOf經理[1] = m1("王")
println(arrayOf經理[1]) // 取出第二個元素
println(arrayOfChar.joinToString()) // 字符串連接 默認逗號
println(arrayOfChar.joinToString("")) // 空字符串連接 ,就是一個完整的字符串
println(arrayOfInt.slice(1..2)) // 字符串區間截取子串
println(arrayOfInt.slice(0..1)) // 字符串區間截取子串
}
idea 查看字節碼 bytecode插件 (jclasslib Bytecode Viewer、ASM Bytecode Viewer )
jclasslib Bytecode Viewer
然后重啟idea===>重新編譯(構建項目)
然后能夠直接看java文件的字節碼
ASM Bytecode Viewer
安裝完了之后同樣需要重新編譯,然后可以直接查看java文件的asm 字節碼
在使用 intellij idea 編寫 kotlin 的時候,我們可以查看當前 kotlin 文件的字節碼。
Tools → Kotlin → Show Kotlin Bytecode
當然字節碼是很難看懂的。沒關系,我們可以把字節碼再反編譯成 java 代碼。
Windows下安裝和配置Kotlin
參考文檔:https://www.kotlincn.net/docs/tutorials/command-line.html
在JDK安裝完成后,就可以安裝Kotlin了。Kotlin是跨平台的,目前支持3種IDE:IntelliJ IDEA、Android Studio和Eclipse。不過在這一節,我們先不考慮IDE的事情。
與Java一樣,安裝Kotlin后,首先看看是否可以通過命令行方式運行Kotlin程序,這是入門Kotlin要進行的第一步。本節只考慮如何在Windows下安裝和配置Kotlin環境,首先進入下面列出的Kotlin官網。
https://kotlinlang.org
將頁面滾動到下半部分,會看到如圖所示的4個下載區域。最右側的Compiler是Kotlin編譯器的下載頁面。
將壓縮包解壓放在自己喜歡的位置,然后仿照“配置JDK環境變量”的方式配置Kotlin的環境變量。
如果在命令行下輸入kotlinc顯示類似如下界面,說明配置成功。
編寫一個hello.kt,如下
fun main(args: Array<String>) { println("Hello, World!") }
使用kotlinc hello.kt編譯上面的文件,這時會在同一目錄下生成一個HelloKt.class,嘗試用java命令來運行HelloKt,結果會是NoClassDefFoundError!
那么,應該如何運行這段代碼呢?根據官網的介紹大概是以下兩種方式。
方式一:使用Kotlin運行這段代碼
D:\IdeaProjects\Helloworld-kotlin\src\basic\kotlin>kotlinc hello.kt
D:\IdeaProjects\Helloworld-kotlin\src\basic\kotlin>kotlin HelloKt
Hello, World!
方式二:使用本地JVM運行這個JAR包
官方的命令為:kotlinc hello.kt -include-runtime -d hello.jar
應該很好理解,運行上述命令之后將得到一個hello.jar,運行這個JAR包:java -jar -hello.jar
D:\labs>java -jar hello.jar Hello, World!
證明Kotlin是完全兼容JVM的
package basic.kotlin.test
/**
* var 與 val 定義變量:
* 1、var內容可變,可以重新賦值
* 2、val內容不可變,不可以重新賦值
* 3、類型推導
* val修飾的變量相當於java中被final修飾的類型變量--------運行時常量
* 當被const修飾時,編譯器會在編譯期間編譯為具體的值,否則就是還是對象的引用 ----------編譯期常量
*
**/
const val FINAL_HELLO_WORLD: String = "HelloWorld" // 不可以重新賦值
var helloWorld: String = FINAL_HELLO_WORLD // 可以重新賦值
val FINAL_HELLO_CHINA = "HelloChina" // 類型推導,由編譯器判斷。
// 默認返回值 Unit 相當於java中的void,就是什么都不返回,也可省略
fun main(args: Array<String>) { // (Array<String>) -> Unit
// FINAL_HELLO_WORLD="qqqq"
helloWorld="123456" // 對var 修飾的常量進行重新賦值
println(helloWorld)
println(FINAL_HELLO_CHINA)
println("hello ${args[0]}")
var arrayOfstr: Array<String> = arrayOf("1","3")
checkArgs(arrayOfstr)
val arg1 = arrayOfstr[0].toInt()
val arg2 = arrayOfstr[1].toInt()
println("$arg1 + $arg2 = ${sum(arg1, arg2)}")
println(int2Long(3))
println(sum(1,3))
println(sum.invoke(1,3)) // invoke是 運算符重載
arrayOfstr.forEach(::println) // reference 寫法
// 不加ForEach@ 是退出forEach所在的函數,后面的代碼不會被執行
// 加ForEach@ 是退出整個for循環,后面的代碼依然會被執行
arrayOfstr.forEach ForEach@{
if(it == "3") return@ForEach
println(it)
}
println("The End")
println(sum)
println(int2Long)
println(::printUsage is ()-> Unit)
}
fun checkArgs(args: Array<String>) {
if (args.size != 2) {
printUsage()
System.exit(-1)
}
}
// 函數定義 --- 無返回值
fun printUsage() {
println("請傳入兩個整型參數,例如 1 2") // (Any?) -> Unit
} // ()->Unit
// lambda 表達式 (Int, Int) -> Int
val sum = { arg1: Int, arg2: Int ->
println("$arg1 + $arg2 = ${arg1 + arg2}")
arg1 + arg2
}
// ()-> Unit
val printlnHello = {
println("Hello")
}
// 匿名函數定義 有返回值
val int2Long = fun(x: Int): Long {
return x.toLong()
}
}
IDEA按鍵失效:常用快捷鍵:Ctrl+C Ctrl+V 選中刪除都不起效,原因是IDEA勾選了Vim模式,
Tools,Vim Emulator,前面會有一個√,可,如圖:
把那個√取消即可解決問題。
kotlin屬性和函數
package basic.kotlin.function
/**
* 測試 屬性和方法 屬性的getter 和setter是默認實現,也可以手動重寫
*
* 默認訪問修飾符 public
* 私有的:protected、private
*
* lateinit 是屬性延遲初始化修飾符
*/
class Score
class Stu{
var age = 0 // getter 和 setter 只能放在當前屬性的正下方
get() {
println("測試getter方法")
return field
}
set(value) {
println("測試setter方法")
field=value
}
lateinit var name: String // 字符串引用類型懶加載賦值 在使用是必須初始化
lateinit var score: Score // 自定義對象類型懶加載賦值 在使用是必須初始化
val e: Score by lazy { // val 修飾的懶加載賦值,通過 by lazy ,在使用是必須初始化
println("初始化 Score")
Score()
}
var cc: String? = null
}
fun main(args: Array<String>) {
val stu = Stu()
println(stu.age) // 等價於 stu.getAge()
stu.age=30
println(stu.age) // 使用之前需要初始化
stu.name="張三" // 使用之前需要初始化
println(stu.name) // lateinit property name has not been initialized
println(stu.e) // 在定義時初始化
stu.score = Score() // 初始化賦值
println(stu.score) // 打印的對象名,使用之前初始化
println(stu.cc?.length) // 空值的條件判斷
}
kotlin的運算符
package basic.kotlin.function
/**
* 運算符:本質上就是一個函數
* + 實際上對應的是kotlin的默認plus 方法
* 我們可以自己定義plus的重載方法 寫自己的運算符實現
*
*/
//c1.plus(c2) 返回值 Complex
class Complex(var real: Double, var imaginary: Double){
// 重載方法:1 參數Complex, 返回值 Complex
operator fun plus(other: Complex): Complex{
return Complex(real + other.real, imaginary + other.imaginary)
}
// 重載方法:2 參數Complex,返回值 Complex
operator fun plus(other: Int): Complex{
return Complex(real + other, imaginary)
}
// 重載方法:3 參數Any,返回值 Int
operator fun plus(other: Any): Int {
return (real + imaginary).toInt()
}
// 重載方法:4
operator fun invoke(): Double{
return Math.hypot(real, imaginary) // q取模運算
}
override fun toString(): String {
return "結果:$real + ${imaginary}"
}
}
//中綴符號表達式,用於兩個對象間的運算
class Book{
infix fun on(any: Any): Boolean{
return false
}
}
class Desk
fun main(args: Array<String>) {
// + 實際上對應的是kotlin的默認plus 方法
println(1 + 2)
val c1 = Complex(3.0, 4.0)
val c2 = Complex(2.0, 5.0)
println(c1 + c2) // 結果:5.0 + 9.0 第一個重載方法 等價於 println(c1.plus(c2))
println(c1 + 5) // 結果:8.0 + 4.0第二個重載方法 等價於 println(c1.plus(5))
println(c1 + "haha") // 7 第三個重載方法 等價於 println(c1.plus("haha"))
println(c1()) // 5.0 第四個重載方法 等價於 println(c1.invoke())
//字符串包含
val arrayOfStr: Array<String> = arrayOf("my","name","is黑客")
if("name" in arrayOfStr){ // 等價於 arrayOfStr.contains("name")
println(arrayOfStr[arrayOfStr.indexOf("name") + 1])
}
if(Book() on Desk()){ // dsl
}
}
分支表達式 if、when
package basic.kotlin.function
/**
* 分支表達式 if 、when
*/
private const val USERNAME = "kotlin"
private const val PASSWORD = "123"
private const val ADMIN_USER = "admin"
private const val ADMIN_PASSWD = "admin"
private const val DEBUG = 1
private const val USER = 0
fun main(args: Array<String>) {
val x = 5
when(x){ // 只會執行其中的一個
is Int -> println("Hello $x") // 判斷 是否是int類型
in 1..100 -> println("$x is in 1..100") // 判斷是否是在區間中
!in 1..100 -> println("$x is not in 1..100") // 判斷是否是不在區間中
args[0].toInt() -> println("x == args[0]") // x 和當前表達式是否一樣
}
// 相當於if else
val wh = when{
args.isNotEmpty() && args[0] == "1"
-> 1
else -> 0
}
println(wh)
// if表達式 帶返回值
val mode = if(args.isNotEmpty() && args[0] == "1"){
DEBUG
}else{
USER
}
println("請輸入用戶名:")
val username = readLine()
println("請輸入密碼:")
val passwd = readLine()
if(mode == DEBUG && username == ADMIN_USER && passwd == ADMIN_PASSWD) {
println("管理員登錄成功")
}else if(username == USERNAME && passwd == PASSWORD){
println("登錄成功")
}else{
println("登錄失敗")
}
}
package basic.kotlin.function
/**
* 跳過continue 和 跳出break 循環
*/
class Student{
fun isNotClothedProperly(): Boolean{
return false
}
}
fun main(args: Array<String>) {
val students = ArrayList<Student>()
val you = Student()
for (student in students){
if(student == you) continue
if(student.isNotClothedProperly()){
break
}
}
}
package basic.kotlin.function
/**
* for 循環 和 while 循環 語句
*/
fun main(args: Array<String>) {
val arrayOfStr: Array<String> = arrayOf("my","name","is黑客")
var x = 5
while(x > 0){
println(x)
x--
}
do{
println(x)
x--
}while (x > 0)
for (arg in arrayOfStr){
println(arg)
}
for((index, value) in arrayOfStr.withIndex()){
println("$index -> $value")
}
for(indexedValue in arrayOfStr.withIndex()){
println("${indexedValue.index} -> ${indexedValue.value}")
}
val list = MyIntList()
list.add(1)
list.add(2)
list.add(3)
for(i in list){
println(i)
}
}
class MyIterator(val iterator: Iterator<Int>){
operator fun next(): Int{
return iterator.next()
}
operator fun hasNext(): Boolean{
return iterator.hasNext()
}
}
class MyIntList{
private val list = ArrayList<Int>()
fun add(int : Int){
list.add(int)
}
fun remove(int: Int){
list.remove(int)
}
operator fun iterator(): MyIterator{
return MyIterator(list.iterator())
}
}
異常捕獲
package basic.kotlin.function
/**
* 異常捕獲
*/
fun main(args: Array<String>) {
val res = try {
val result = 1/0
}catch (e: Exception){
println("程序出現了未知異常,可能是您的人品太差了。${e.message}")
0
}finally {
println("謝謝您使用我們的加法計算器")
}
println(res)
}
具名參數:參數賦值到具體名稱,沒有順序
變長參數:在java里是最后一個參數,在kotlin沒有這種限制
默認參數:調用時不傳入參數,可以采用設置默認值
package basic.kotlin.function
/**
* 具名參數:參數賦值到具體名稱,沒有順序
* 變長參數:在java里是最后一個參數,在kotlin沒有這種限制
* 默認參數:調用時不傳入參數,可以采用設置默認值
*/
fun main(vararg args: String) {
// for (arg in args){
// println(arg)
// }
val list = arrayListOf(1,3,4,5)
val array = intArrayOf(1,3,4,5)
hello(3.0, *array)
}
fun hello(double: Double, vararg ints: Int, string: String = "Hello"){
println(double)
ints.forEach(::println)
println(string)
}
先以 Http Servlet 創建 Web 應用 為例
在導入工程后,通過gradle的工具創建生成war,war包的名稱和settings.gradle的 rootProject.name = 'servlet-web-applications' 一致
方式一:打成war包運行
手動放到tomcat容器,雙擊運行tomcat。
方式二:
IDEA 中添加tomcat容器的方式運行工程