注:編碼工具為IntelliJ
目錄
介面
示例
定義變數
示例
變數默認值
抽象類
示例
實作介面
泛型
泛型類
泛型函式
泛型實作自定義map變換
泛型類聯合泛型函式實作
泛型函式實作
型別約束
泛型vararg引數
vararg示例
泛型vararg
型別判斷
out和in關鍵字
擴展
擴展函式
擴展屬性
對泛型擴展
infix:中綴運算式
結合泛型使用
集合運算子
map
flatMap
filter
zip
與Java的互操作
用可空型別接收Java的資料
@file:JvmName()
@JvmField
@JvmOverloads
@JavaStatic
單例
餓漢式
懶漢式
介面
介面默認是open的,介面成員默認也是open的,
示例
interface InterfaceTest {
fun test()
}
class InterfaceTestImpl : InterfaceTest{
override fun test() {
println("這是實作自InterfaceTest的方法")
}
}
fun main() {
InterfaceTestImpl().test()
}
輸出:
這是實作自InterfaceTest的方法
定義變數
實作類可以通過建構式引數或者在類內部兩種方式重寫介面的變數,
介面內部可以有函式默認實作,
示例
interface InterfaceVariable {
var name : String
val des: String
fun show(){
println("name = $name, des = $des")
}
}
class InterfaceVariableImpl(override var name: String,
override val des: String) : InterfaceVariable
class InterfaceVariableImpl2(name: String, des: String): InterfaceVariable{
override var name: String = name
override val des: String = des
}
fun main() {
InterfaceVariableImpl("Happy", "Word").show()
InterfaceVariableImpl2("Terminal", "When").show()
}
輸出:
name = Happy, des = Word
name = Terminal, des = When
變數默認值
介面定義的變數不可以用=直接賦值,但是val修飾的變數可以用get屬性賦值,
有默認值的介面變數,可以重寫,也可以不重寫,
interface InterfaceVariable2 {
val randNum: String
get() = (1..100).shuffled().first().toString()
val des : String
get() = "不要問我從哪里來"
fun show(){
println("randNum = $randNum, des = $des")
}
}
class InterfaceVariable2Impl: InterfaceVariable2 // 介面內變數有默認值,則可以不多載
class InterfaceVariable2Impl2(randNum: String, des: String): InterfaceVariable2{
override val randNum: String = randNum
override val des: String = des
}
fun main() {
InterfaceVariable2Impl().show()
InterfaceVariable2Impl2("hahaha", "song").show()
}
輸出:
randNum = 89, des = 不要問我從哪里來
randNum = hahaha, des = song
抽象類
抽象類默認是open的,抽象類的抽象函式和抽象屬性默認也是open的,
抽象類可以有非抽象成員變數和非抽象函式,
非抽象成員變數和非抽象函式如果想要被重寫,需要添加open關鍵字,
示例
abstract class Abstract(age: Int) {
abstract var name: String
open var age: Int = age
open fun show() {
println("age = $age")
}
abstract fun show2()
}
class SubAbstract(override var name: String, override var age: Int) : Abstract(age) {
override fun show2() {
println("name = $name, age = $age")
}
override fun show() {
println("override show")
}
}
fun main() {
val subAbstract = SubAbstract("Sjh", 30)
subAbstract.show()
subAbstract.show2()
}
輸出:
override show
name = Sjh, age = 30
實作介面
抽象類可以實作介面,既可以重寫介面成員,也可以不重寫,
interface Animal{
fun show()
}
abstract class Cat: Animal
abstract class Dog: Animal{
override fun show() {
println("Dog重寫了show")
}
}
class Poodle: Dog()
fun main() {
Poodle().show()
}
輸出:
Dog重寫了show
泛型
泛型類
class GenericClass<T>(val t: T){
fun printAny() = println(t)
}
fun main() {
GenericClass(123).printAny()
GenericClass("hello").printAny()
GenericClass(123.3987f).printAny()
GenericClass('C').printAny()
GenericClass(3214.908).printAny()
}
輸出:
123
hello
123.3987
C
3214.908
泛型函式
fun <TYPE> getSelf(t: TYPE) = t.takeIf { t != null } ?: "t is null"
fun main() {
println(getSelf(null))
println(getSelf("今天星期天"))
println(getSelf(234))
}
輸出:
t is null
今天星期天
234
泛型實作自定義map變換
map變換把一種型別輸入,變換為一種型別輸出
泛型類聯合泛型函式實作
package step_six
class GenericClassMap<I>(val input: I, val isMap : Boolean = true){
fun <O> map(action:(I)->O) = action(input).takeIf { isMap }
}
fun main() {
println(GenericClassMap("i love this").map {
it.uppercase()
})
}
輸出:
I LOVE THIS
泛型函式實作
private fun <I, O> map(input: I, isMap: Boolean = true, action: (I) -> O)
= action(input).takeIf { isMap }
fun main() {
println(map("into the unknown") {
it.uppercase()
})
}
輸出:
INTO THE UNKNOWN
型別約束
類似于Java的T extends CharSequence,Kotlin寫法為T: CharSequence,
open class SuperObject(val name: String)
open class Human(val humanName: String): SuperObject(humanName)
class Man(val manName: String): Human(manName)
class Woman(val womanName: String): Human(womanName)
class Other(val name: String)
fun <T: Human> show(t: T){ // 只能接收Human及子類物件
println("name = ${t.humanName}")
}
fun main() {
// show(SuperObject("super object"))// 編譯不通過
show(Human("human"))
show(Man("man"))
show(Woman("woman"))
// show(Other("other"))// 編譯不通過
}
輸出:
name = human
name = man
name = woman
泛型vararg引數
vararg相當于Java的可變引數,
vararg示例
fun show(vararg arr: Int){
arr[0] = 1
arr.forEach {
println(it)
}
}
fun main() {
show(-1)
}
輸出:
1
泛型vararg
泛型vararg引數,只能用out修飾的泛型引數陣列接收,只能讀取其中元素,不能修改,
private fun <T> show(vararg ts: T){
ts.forEach {
print("$it ")
}
}
fun main() {
show(1, 2, 3)
}
輸出:
1 2 3
型別判斷
泛型引數進行is和as操作的時候,后面要跟可空資料型別,因為泛型可以接收null,
private fun <T> show(t : T){
if(t is String?){
println(t?.length ?: null)
}else if(t is Int?){
println(t ?: null)
}else{
println("其他型別")
}
}
fun main() {
show(null)
show("Hope")
show(123)
show('C')
}
輸出:
null
4
123
其他型別
out和in關鍵字
out:
out T相當于Java的? extends T,與Java的不同點是out T只能在類或介面上宣告,
out T在類或介面上宣告時,該類的所有函式只能將T型別變數作為回傳值,不能作為函式入參,
in:
in T相當于Java的? super T,與Java的不同點是in T只能在類或介面上宣告,
in T在類或介面上宣告時,該類的所有函式只能將T型別變數作為入參,不能作為函式回傳值,
擴展
擴展函式
在類的外部定義的類的成員函式,可以和類內部的成員函式一樣呼叫,可以訪問類內部成員,
class ExpandTest(val info: String)
fun ExpandTest.show() = println(info)
fun main() {
ExpandTest("擴展函式").show()
}
輸出:
擴展函式
擴展屬性
在類的外部定義的類的成員屬性,可以和類內部的成員屬性一樣呼叫,
class ExpandField(val info: String)
val ExpandField.infoLength
get() = info.length
fun main() {
println(ExpandField("擴展屬性").infoLength)
}
輸出:
4
注意:
擴展函式和擴展屬性不限制訪問范圍的話,全域都可以訪問,
如果想讓可空型別也可以呼叫擴展函式或擴展屬性的話,則需要對可空型別進行擴展,
可以將擴展函式和擴展屬性定義到單獨的檔案中,便于查找和維護,
對泛型擴展
內置函式如:apply、let、run、with、also、takeIf、takeUnless的實作原理,
private fun <T> T.log() = println(this)
fun main() {
123.log()
"abc".log()
'C'.log()
null.log()
}
輸出:
123
abc
C
null
infix:中綴運算式
infix fun String.infixTest(i: Int){
println("$this:::$i")
}
fun main() {
"abcd" infixTest 1324
}
輸出:
abcd:::1324
結合泛型使用
應用范圍更廣,如 to,可以生成任意型別的Pair變數,
private infix fun <T, X> T.union(x: X){
println("t = $this, x = $x")
}
fun main() {
8734.2 union "abc"
}
輸出:
t = 8734.2, x = abc
tips:導包可以用as取別名,可以提高開發效率,解決包沖突問題,
集合運算子
map
可以將集合元素做一些轉換后添加到另一個集合中,
fun main() {
listOf("Beijing", "Shanghai", "Nanjing").map {
it.length
}.forEach{
print("$it ")
}
}
輸出:
7 8 7
flatMap
可以將集合元素做一些轉換,flatMap的lambda必須回傳一個集合,
fun main() {
listOf("張三", "李四", "王五").flatMap {
listOf("&$it&")
}.forEach { print("$it ") }
}
輸出:
&張三& &李四& &王五&
filter
根據過濾條件挑選符合的元素,
fun main() {
listOf("Hi", "Hello", "What", "World", "Happy")
.filter {it.contains("H")}
.forEach { print("$it ") }
}
輸出:
Hi Hello Happy
zip
合并兩個集合,將對應下標的元素封裝成一個Pair,最終放到一個新的集合里,
fun main() {
val words = listOf("Hi", "Hello", "Hope", "Happy", "Work")
val lengths = listOf(2, 5, 4, 5, 4)
words.zip(lengths).forEach {
println("word = ${it.first}, length = ${it.second}")
}
}
輸出:
word = Hi, length = 2
word = Hello, length = 5
word = Hope, length = 4
word = Happy, length = 5
word = Work, length = 4
與Java的互操作
用可空型別接收Java的資料
Java代碼:
package communicate_with_kotlin;
public class ProvideValue {
public static String getInfo(){
return null;
}
public static String getString(){
return "測驗";
}
}
Kotlin代碼:
import communicate_with_kotlin.ProvideValue
fun main() {
val info: String? = ProvideValue.getInfo()
val string: String? = ProvideValue.getString()
println(info?.length ?: "info是空值")
println(string?.length ?: "string是空值")
}
輸出:
info是空值
2
@file:JvmName()
用于定義Kotlin檔案生成的類名,必須寫在包名前面,
Kotlin代碼:
@file:JvmName("NewClassName")
package step_six
fun jvmName(){
println("測驗JvmName")
}
Java代碼:
import step_six.NewClassName;
public class JvmNameTest {
public static void main(String[] args) {
NewClassName.jvmName();
}
}
輸出:
測驗JvmName
@JvmField
可以使Java代碼可以直接訪問Kotlin的變數,而不需要通過get方法,
Kotlin代碼:
package step_six
class JvmFieldTest(@JvmField val msg: String)
Java代碼:
import step_six.JvmFieldTest;
public class JvmField {
public static void main(String[] args) {
System.out.println(new JvmFieldTest("JvmField測驗").msg);
}
}
輸出:
JvmField測驗
@JvmOverloads
可以使Java代碼能夠用Kotlin的默認引數特性,
Kotlin代碼:
package step_six
@JvmOverloads
fun show(name: String, age: Int = 99, gender: Char = 'F')
{
println("name = $name, age = $age, gender = $gender")
}
Java代碼:
package communicate_with_kotlin;
import step_six.JvmOverloadsTestKt;
public class JvmOverloads {
public static void main(String[] args) {
JvmOverloadsTestKt.show("ss");
JvmOverloadsTestKt.show("gg", 14);
JvmOverloadsTestKt.show("h", 30);
}
}
輸出:
name = ss, age = 99, gender = F
name = gg, age = 14, gender = F
name = h, age = 30, gender = F
@JavaStatic
使Java代碼像呼叫Java的static方法一樣呼叫Kotlin的函式,
Kotlin代碼:
package step_six
class JvmStaticTest {
companion object{
@JvmStatic
fun show(){
println("JvmStatic測驗")
}
}
}
Java代碼:
public class JvmStatic {
public static void main(String[] args) {
JvmStaticTest.show();
}
}
輸出:
JvmStatic測驗
單例
餓漢式
object EHanSingleton{
fun show(){
println("Kotlin餓漢式單例")
}
}
fun main() {
EHanSingleton.show()
}
輸出:
Kotlin餓漢式單例
懶漢式
package step_six
class LanHanSingleton private constructor(){
init{
println("主建構式執行了")
}
companion object{
val INSTANCE: LanHanSingleton by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED){
LanHanSingleton()
}
}
fun show(){
println("Kotlin懶漢式單例")
}
}
fun main() {
LanHanSingleton.INSTANCE.show()
LanHanSingleton.INSTANCE.show()
}
輸出:
主建構式執行了
Kotlin懶漢式單例
Kotlin懶漢式單例
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/353444.html
標籤:其他
