Kotlin基础语法
Kotlin内置数据类型
名称 | 释义 |
---|---|
String | 字符串 |
char | 字符 |
Boolean | 布尔型 |
Int | 整型 |
Float | 单精度浮点型 |
Double | 双精度浮点型 |
List | 集合 |
Set | 无重复元素集合 |
Map | 键值对集合 |
变量
可读可写变量
var name: String = "Kotlin"
name = "C++"
println(name)
可读变量
val name: String = "Kotlin"
//下列变量不可修改,因为声明成val,只能进行读操作,不能进行写操作
//name = "C++"
println(name)
自动类型推导机制
根据定义变量时进行初始化,系统可以根据初始化值自动进行类型推导,进而可以省略类型声明
val name = "Kotlin" //String
val age = 5 //Int
val sex = m' //char
val score = 99.99 //Doble
when表达式
val week = 5
val info = when(week){
1-> "星期一"
2-> "星期二"
3-> "星期三"
4-> "星期四"
5-> "星期五"
6-> "星期六"
7-> "星期天"
else-> "错误类型"
}
println(info)
range表达式
val score = 70
when (score) {
in 0..59 -> {
println("不及格")
}
in 60 ..79 -> {
println("及格")
}
in 80 .. 89 -> {
println("良好")
}
else -> {
println("优秀")
}
}
字符串模版
val name = "Kotlin"
val age = 7
val score = 32
val detail = "I am $name and $age,I got ${score+10} in the last test."
println(detail)
函数
函数定义
-
在Kotlin中函数默认访问类型为Public,此处我声明为private
-
fun
为声明函数关键字 -
add
为函数名 -
a:Int,b:Int
为函数形参 -
形参列表后面有一个
:Int
,代表函数返回Intprivate fun add(a:Int,b:Int):Int{
val result = a+b
println(result)
return result
}
函数简写
当函数体只有一行代码时,可以不写括号,直接在等号后面接代码即可
private fun add(a:Int,b:Int) = println(a+b)
若函数需要返回值,则直接将计算结果接在等号后面返回
private fun add(a:Int,b:Int):Int = a+b
默认参数
fun printfInfo(name:String,age:Int) = println("I am $name and $age")
fun printfInfo(name:String="Li",age:Int) = println("I am $name and $age")
fun printfInfo(name:String="Li",age:Int=20) = println("I am $name and $age")
具名函数参数
具名参数可以任意调整实参的顺序
printfInfo(age = 10,name = "Kotlin")
...
fun printfInfo(name:String,age:Int) = println("I am $name and $age")
Unit函数
在JAVA中void为空返回类型,是一个关键字
在Kotlin中Unit是一个类类型,为函数默认返回类型
private fun exe():Unit{
return println()
}
反引号函数
打印分数(20.22)
...
private fun `打印分数`(score:Double){
println("分数=$score")
}
匿名函数
val len = "Kotlin".count()
println("len=$len")
val len1 = "Kotlin,in".count { it->
it == 'i'
}
println("len1=$len1")
隐式返回
函数声明
val printfScore:(score:Double)->String
函数实现,匿名函数无需使用return
返回结果,以最后一行作为返回值进行返回
printfScore = { it->
println("score$it")
"打印成功!"
}
函数调用
printfScore(50.50)
函数作为形参
const val NAME = "Kotlin"
const val AGE = 10
//...
JudgeInfo("Kotlin",10){ info,code->
println("info=$info,code=$code")
}
//...
fun JudgeInfo(name:String,age:Int,respond:(String,Int)->Unit){
val result = name == NAME && age == AGE
if (result == true){
respond("success",200)
}else{
respond("failed",404)
}
}
函数引用
const val NAME = "Kotlin"
const val AGE = 10
//...
JudgeInfo("Kotlin",10,::printfInfo)
fun printfInfo(info:String,code:Int) = println("info=$info,code=$code")
//...
fun JudgeInfo(name:String,age:Int,respond:(String,Int)->Unit){
val result = name == NAME && age == AGE
if (result == true){
respond("success",200)
}else{
respond("failed",404)
}
}
函数作为返回值
const val NAME = "Kotlin"
const val AGE = 10
//...
val exe = JudgeInfo()
println(exe("Kotlin",10))
//...
fun JudgeInfo():(name:String,age:Int)->Boolean{
return { name,age->
val result = name ==NAME && age ==AGE
result
}
}
可空性
在Kotlin中不能直接给一个变量赋值null
,这也极大减少了空异常频发问题
如果需要给一个变量赋null,则需要在声明时,在变量类型后面加一个?
,示意准许此变量在程序中为null
val name:String ? = null
println(name)//打印出null
将一个可空类型字符串变量转为大写,需要在调用uppercase
函数时前面加一个?
,代表如果name不为空则执行uppercase
函数,否则不执行?
后面的函数
var name:String ? = null
name = "kotlin"
val msg = name?.uppercase()
println(msg)
高级函数 let
var name:String ? = null
name = "kotlin"
val msg = name?.let {
it.uppercase()
}
println(msg)
非空断言
var name:String ? = null
name = "kotlin"
val msg = name!!.uppercase()
println(msg)
空合并操作符
var name:String ? = null
println(name ?: "name为空!")
高级函数
apply函数
-
apply函数始终返回对象本身
-
apply匿名函数在内部持有当前对象
this
val languages = arrayOf("C++","JAVA","Kotlin","C")
//apply函数始终返回对象本身,且apply匿名函数在内部持有当前对象this
languages.apply {
println("数组长度=${size}")
}.apply {
forEach {
println(it)
}
}.apply {
println("遍历数组完毕")
}
run函数
-
以最后一行作为返回值返回
-
匿名函数内部持有当前对象
this
val len = languages.run {
filter {
it.contains('C')
}.size
}
println("包含字符C的元素个数=${len}")
with函数
-
以最后一行作为返回值返回
-
匿名函数内部持有当前对象
this
-
不能以拓展函数形式调用,只能将当前对象以形参形式传递
val languages = arrayOf("C++","JAVA","Kotlin","C")
val len = with(languages){
filter {
it.contains('C')
}.size
}
println("包含字符C的元素个数=${len}")
also函数
-
also函数始终返回对象本身
-
匿名函数内部持有
it
val languages = arrayOf("C++","JAVA","Kotlin","C") languages.also { println(it.first()) }.also { println(it.last()) }.also { println("元素个数=${it.size}") }
takeIf函数
如果takeIf
函数内部为true
则返回对象本身,否则返回null
const val NAME = "Kotlin"
const val AGE = 10
fun main() {
val result = JudgeInfo("Kotlin",10)
println(result)
}
fun JudgeInfo(name:String,age:Int):String{
return name.takeIf { name`NAME&&AGE`age } ?: "信息不匹配!"
}
takeUnless函数
takeUnless函数与takeIf函数功能相反,如果takeUnless
内部为true则返回null,否则返回对象本身
集合
List
val languages:List<String> = listOf<String>("C++","C","JAVA","Kotlin","Dart")
// public operator fun get(index: Int): E
//与C++的运算符重载类似
println("第一个元素:${languages[0]}")
languages.forEach {
println(it)
}
列表越界处理
//方法一
val result = languages.getOrElse(5){
"数组越界"
}
println(result)
//方法二
val result1 = languages.getOrNull(1000) ?: "数组越界"
println(result1)
可变List
val languages = mutableListOf("C++","C","JAVA","Kotlin","Dart")
-
删除List中包含字符C的元素
languages.removeIf { it.contains('C') } languages.forEach{ println(it) }
-
添加元素
通过运算符重载函数为List添加新元素
public inline operator fun MutableCollection.plusAssign(element: T) {
this.add(element)
}
languages += "C#"
languages += "Basic"
languages.forEach{
println(it)
}
- 遍历List
forEach
languages.forEach{
println(it)
}
for-in
for(element in languages){
println(element)
}
forEachIndexed
languages.forEachIndexed { index, s ->
println("第${index+1}元素=$s")
}
Set
不允许存在重复元素,如果存在重复元素,会自动忽略
下列输出C++ C JAVA Kotlin Dart
val languages:Set<String> = setOf<String>("C++","C","JAVA","Kotlin","Dart","C++")
languages.forEach {
print("$it ")
}
println()
元素读取
languages.elementAt(0)
防止下标越界而导致程序崩溃
//法一
val result1 = languages.elementAtOrNull(1000) ?: "越界"
//法二
val result2 = languages.elementAtOrElse(1000){
"越界"
}
可变Set
val languages:MutableSet<String> = mutableSetOf<String("C++","C","JAVA","Kotlin","Dart","C++")
languages += "Basic"
languages -= "C++"
languages.forEach {
print("$it ")
}
数组
数组定义
val languages = arrayOf<String>("C++","C","JAVA","Kotlin","Dart","C++") //对象数组
val intNumbers = intArrayOf(1,2,3,4,5)
val doubleNumbers = doubleArrayOf(10.1,11.2,12.1)
val charArray = charArrayOf('a','b','c')
读取数组元素
println(languages[0])
val result1 = languages.elementAtOrElse(1000){
"越界"
}
val result2 =languages.elementAtOrNull(1000) ?: "越界"
println(result1)
println(result2)
Map
map定义
//法一
val map:Map<String,Int> = mapOf("C" to 1,"C++" to 2,"Kotlin" to 3)
//法二
val map1:Map<String,Int> = mapOf(Pair("C",1),Pair("C++",2),Pair("Kotlin",3))
读取map元素,如果读取map中没有的元素,则返回null
val value = map["C"]
println(value)
定义默认值
val value = map.getOrDefault("Go",-1)
println(value)
通过匿名函数定义错误读取
val value = map.getOrElse("Go"){
"没有对应的值"
}
println(value)
遍历map
-
法一
val map:Map<String,Int> = mapOf("C" to 1,"C++" to 2,"Kotlin" to 3)
map.forEach { (_, value) ->
print("$value ")
} -
法二
val map:Map<String,Int> = mapOf("C" to 1,"C++" to 2,"Kotlin" to 3)
map.forEach {
print("${it.value} ")
} -
法三
val map:Map<String,Int> = mapOf("C" to 1,"C++" to 2,"Kotlin" to 3)
for (entry in map) {
print("${entry.value} ")
}
可变Map
val map:MutableMap<String,Int> = mutableMapOf("C" to 1,"C++" to 2,"Kotlin" to 3)
map += Pair("JAVA",4)
map += "Basic" to 5
map -= "C"
map.forEach { (_, value) ->
print("$value ")
}
类
在Kotlin中,类的成员属性默认访问权限为public
class Student{
var name:String = "Kotlin"
//下列get和set默认存在
get() = field
set(value) {
field = value
}
var sex:Char = 'm'
get() = field.uppercaseChar()
set(value) {
field =value.lowercaseChar()
}
private var age:Int = 0
}
fun main() {
val zhangsan = Student()
println(zhangsan.name)
}
主构造函数
//主构造函数,下列形参为输入类型,不能直接使用,需要通过接收成为变量才能使用
class Student(name: String, age:Int){
fun print(){
//此处不能直接调用name
// println(name)
}
}
通过下列两种方式,主构造函数的形参就可以在类中使用
//法一
class Student(var name: String, var age:Int){
fun print(){
println(name)
}
}
//法二
class Student(name: String, age:Int){
var name = name
var age = age
fun print(){
println(name)
}
}
次构造函数
次构造函数必须调用主构造函数
class Student(name: String){
var name:String = name
var age:Int = 0
var score:Double = 0.0
//次构造函数必须调用主构造函数
constructor(name: String,age:Int):this(name){
this.name = name
this.age = age
}
constructor(name: String,age:Int,score:Double):this(name){
this.name = name
this.age = age
this.score = score
}
}
fun main() {
val lisi = Student("李四")
val zhangsan = Student("张三",20)
val wangwu = Student("王五",20,50.50)
println(zhangsan.score)
}
lateinit 延迟初始化
class Student{
lateinit var name:String
fun initName(name:String){
this.name = name
}
fun showName(){
val flag = ::name.isInitialized//判断是否初始化
if(flag){
println(name)
}else{
println("未初始化name")
}
}
}
fun main() {
println(Student().showName())
}
lazy 惰性初始化
class Student{
//当调用的时候才初始化
val name:String by lazy { readName() }
private fun readName(): String {
println("loading...")
println("loading...")
println("loading...")
return "FranzLiszt"
}
}
fun main() {
val zhangsan = Student()
Thread.sleep(3000)
println(zhangsan.name)
}
继承和重载
在Kotlin中,类默认是final修饰,不能被继承;只有通过open修饰才能被继承
//类默认是final修饰,不能被继承;只有通过open修饰才能被继承
open class Person(val name:String){
private fun printfName() = println("parent class name:$name")
open fun showName() = println(printfName())
}
class Student(val subname:String): Person(subname){
private fun printfName() = println("sub class name:$name")
override fun showName() = printfName()
}
fun main() {
val person:Person = Student("张三")
person.showName()
}
companion objec 伴生对象
伴生对象,与Java的Static类似,同样无论调用多少次,伴生对象只会初始化一次
class Student(){
//伴生对象,与Java的Static类似
companion object{
private val name = "student"
fun showName() = println(name)
}
}
fun main() {
println(Student.showName())
}
内部类
内部的类不能访问外部类属性,通过添加inner修饰,成为内部类才能访问
class Person(name:String){
val name = name
//内部的类不能访问外部类属性,通过添加inner修饰,成为内部类才能访问
inner class Male{
fun show() = println("male $name")
}
inner class Female{
fun show() = println("female $name")
}
}
fun main() {
val p = Person("zs")
p.Male().show()
}
嵌套类
嵌套类的内部的类不能访问外部类属性
class Person(name:String){
val name = name
class Male{
//不能访问外部类属性
//fun show() = println("male $name")
}
class Female{
fun show() = println("嵌套类")
}
}
fun main() {
Person.Female().show()
}
数据类
定义数据类
data class Student(var name:Student,var age:Int)
反编译上面的数据类,可以看见除了成员变量的get()、set()函数外,还拓展了拷贝函数、toString()、equals()函数等;比起JAVA的JavaBean更加丰富;其中上述扩展的函数只会覆盖主构造函数的成员属性,不会覆盖次构造函数的成员属性
public final class Student {
@NotNull
private Student name;
private int age;
@NotNull
public final Student getName() {
return this.name;
}
public final void setName(@NotNull Student var1) {
Intrinsics.checkNotNullParameter(var1, "<set-?>");
this.name = var1;
}
public final int getAge() {
return this.age;
}
public final void setAge(int var1) {
this.age = var1;
}
public Student(@NotNull Student name, int age) {
Intrinsics.checkNotNullParameter(name, "name");
super();
this.name = name;
this.age = age;
}
@NotNull
public final Student component1() {
return this.name;
}
public final int component2() {
return this.age;
}
@NotNull
public final Student copy(@NotNull Student name, int age) {
Intrinsics.checkNotNullParameter(name, "name");
return new Student(name, age);
}
// $FF: synthetic method
public static Student copy$default(Student var0, Student var1, int var2, int var3, Object var4) {
if ((var3 & 1) != 0) {
var1 = var0.name;
}
if ((var3 & 2) != 0) {
var2 = var0.age;
}
return var0.copy(var1, var2);
}
@NotNull
public String toString() {
return "Student(name=" + this.name + ", age=" + this.age + ")";
}
public int hashCode() {
Student var10000 = this.name;
return (var10000 != null ? var10000.hashCode() : 0) * 31 + Integer.hashCode(this.age);
}
public boolean equals(@Nullable Object var1) {
if (this != var1) {
if (var1 instanceof Student) {
Student var2 = (Student)var1;
if (Intrinsics.areEqual(this.name, var2.name) && this.age ` var2.age) {
return true;
}
}
return false;
} else {
return true;
}
}
}
运算符重载
下列列出一些常用的重载运算符
表达式 | 翻译为 |
---|---|
a + b | a.plus(b) |
a - b | a.minus(b) |
a * b | a.times(b) |
a / b | a.div(b) |
a % b | a.rem(b) |
a[i] | a.get(i) |
a += b | a.plusAssign(b) |
a > b | a.compareTo(b) > 0 |
a < b | a.compareTo(b) < 0 |
a++ | a.inc() |
a-- | a.dec() |
下面重写了加减乘除四个运算符,可以与C++的运算符重载做对比,差异如下
-
C++直接对运算符进行重新标识,而Kotlin需要进行转化,例如重载加号运算符,需要改为
plus
函数class Calculation(private val num1:Int){
//重载加号运算符
operator fun plus(param:Calculation):Calculation = Calculation(num1+param.num1)//重载减号运算符 operator fun minus(param:Calculation):Calculation = Calculation(num1-param.num1) //重载乘号号运算符 operator fun times(param:Calculation):Calculation = Calculation(num1*param.num1) //重载除号运算符 operator fun div(param:Calculation):Calculation{ if (param.num1 ` 0 )return Calculation(0) return Calculation(num1/param.num1) } fun printfNum() = println("num=$num1")
}
fun main(){
val example1 = Calculation(5)
val example2 = Calculation(10)
val result = example1 + example2
result.printfNum()
}
枚举类
data class WeekInfo(var info:String)
enum class Week(private val weekInfo: WeekInfo) {
Sunday(WeekInfo("星期天")),
Monday(WeekInfo("星期一")),
Tuesday(WeekInfo("星期二")),
Wednesday(WeekInfo("星期三")),
Thursday(WeekInfo("星期四")),
Friday(WeekInfo("星期五")),
Saturday(WeekInfo("星期六"));
fun show() = println("info = ${weekInfo.info}")
fun update(weekInfo: WeekInfo){
this.weekInfo.info = weekInfo.info
println("info = ${weekInfo.info}")
}
}
fun main(){
Week.Friday.show()
Week.Sunday.update(WeekInfo("XINGQITIAN"))
}
代数数据类型
enum class Judge{
Bad,
Mid_Good,
Superior
}
fun testScore(score: Judge): String =
when (score) {
Judge.Bad -> "不及格"
Judge.Mid_Good -> "良好"
Judge.Superior -> "优秀"
}
fun main(){
println(testScore(Judge.Superior))
}
密封类
sealed class Scores{
object Fail:Scores()
object Pass:Scores()
object Superior:Scores()
}
fun testScore(score: Scores): String =
when (score) {
is Scores.Fail -> "不及格"
is Scores.Pass -> "良好"
is Scores.Superior -> "优秀"
}
fun main(){
println(testScore(Scores.Pass))
}
接口
在Kotlin中,接口实现类不仅要实现其接口的函数,还需要重写其成员变量
interface Information{
var name:String
var age:Int
fun showInfo()
}
class Student(stuName:String, stuAge:Int):Information{
override var name: String = stuName
override var age: Int = stuAge
override fun showInfo() {
println("name=$name,age=$age")
}
}
fun main(){
val zhangsan:Student = Student("张三",20)
zhangsan.showInfo()
}
抽象类
abstract class Base{
fun run(){
running(getAnimalName())
eating(getAnimalName())
}
abstract fun getAnimalName():String
abstract fun running(name:String)
abstract fun eating(name:String)
}
class Cat:Base(){
override fun getAnimalName(): String = "Cat"
override fun running(name:String) = println("$name running")
override fun eating(name:String) = println("$name eating")
fun show(){
super.run()
}
}
fun main(){
val cat:Cat = Cat()
cat.show()
}
泛型类
class BasePrintf<T> (private val obj:T){
fun printf() = println("输出结果:$obj")
}
data class Student(val name:String,val age:Int)
data class Teacher(val name:String,val age:Int,val id:Int)
fun main() {
val zhangsan = Student("张三",20)
val lisi = Teacher("李四",30,111)
BasePrintf(zhangsan).printf()
BasePrintf(lisi).printf()
BasePrintf(111).printf()
BasePrintf("aaa").printf()
}
vararg 动态参数
class Person<T>(private vararg val params:T){
//out的作用是T只能被读取,不能修改
private val arrays: Array<out T> = params
fun show(index:Int): T = arrays[index]
fun<o> map(index:Int,action:(T)->o) = action(arrays[index])
}
fun main() {
val param = Person("Kotlin",20,false,99.99)
println(param.show(0))
println(param.show(1))
param.map(3){
println(it)
}
}
协变&逆变
协变
-
在泛型前加out,代表此泛型只能被读取不能被修改
-
泛型的子类对象可以赋值给泛型的父类对象
interface Producer<out T>{
fun produce():T
}
逆变
-
在泛型前加in,代表此泛型只能被修改不能被读取
-
泛型的具体父类可以赋值给泛型声明处的子类
interface Consumer<in T>{
fun consumer(param:T)
}
扩展函数
class Student(val name:String,val age:Int)
fun Student.printf() = println("name=$name,age=$age")
fun main() {
val zhangsan = Student("张三",20)
zhangsan.printf()
}
单例模式
饿汉式
object Student
懒汉式
class Student{
companion object{
private var instance:Student ? = null
get() {
if (field ` null) field = Student()
return field
}
fun getInstanceAction():Student = instance!!
}
}
懒汉式-加锁
class Student{
companion object{
private var instance:Student ? = null
get() {
if (field ` null) field = Student()
return field
}
@Synchronized
fun getInstanceAction():Student = instance!!
}
}
懒汉式-双重校验
class Student private constructor(){
companion object{
val instance:Student by lazy (mode = LazyThreadSafetyMode.SYNCHRONIZED){Student()}
}
}