kotlin学习笔记——接口抽象类泛型扩展集合操作符与java互操作性单例(代码片段)

迷月星辰 迷月星辰     2023-01-30     144

关键词:

注:编码工具为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懒汉式单例

java实训笔记——-抽象类-接口-泛型-集合

1.1方法的可变参数从JDK1.5之后,定义方法时参数的个数可以变化语法:最后一个数据类型后增加3个点注意:1.可变参数只能处于参数列表的最后;2.一个方法中最多只能包含一个可变参数;3.可变参数的本质就是一个数组,因此... 查看详情

类泛型--必须继承接口

where用法 查看详情

设计模式学习笔记(十六:桥接模式)

1.1概述  将抽象部分与它的实现部分分离,使他们都可以独立地变化。这就是桥接模式的定义。  抽象类或接口中可以定义若干个抽象方法,习惯上将抽象方法称作操作。抽象类或接口使程序的设计者忽略操作的细... 查看详情

unity的c#学习——泛型的创建与继承泛型集合类泛型中的约束和反射(代码片段)

文章目录泛型1、泛型的名称由来2、泛型的创建与调用3、泛型类与非泛型类的继承4、泛型集合类5、泛型中约束与反射的应用5.1约束——限定可使用的数据类型5.2反射——获取要使用的数据类型泛型C#泛型是C#2.0中引入的一个非常... 查看详情

快速上手kotlin接口抽象类及泛型(代码片段)

接口定义    kotlin规定所有的接口属性和函数实现都要使用override关键字,接口中定义的函数并不需要open关键字修饰,他们默认就是open的代码展示:packagecom.wustyq.kotlinstudyinterfaceMovablevarmaxSpeed:Intvarwheels:Intfunmove(movabl... 查看详情

20191209-20191210学习总结

20191209学习总结泛型类泛型集合类可以将类型参数用作它所存储的对象的类型的占位符。一般使用E、T、K、V、?E代表element,T代表type,K代表key,V代表value。父类泛型,子类也必须是泛型。自定义栈运用栈的特点:内存快一些,后... 查看详情

day002-list类泛型(代码片段)

1.集合 集合是容器,可以存储任意类型的数据,集合的长度可变。 1.1集合和数组的比较 1.2集合分类 单列集合:每次存储时,存储一个元素(Collection),包括:list、set 双列集合:每次存储时,存储两个元素(Map) 1.3Collection ... 查看详情

大话设计模式抽象接口集合泛型

目录什么是抽象?注意什么是接口?那么,类一旦实现了接口呢?抽象类和接口的区别我们刚开始用的是数组,那数组的优缺点是什么?优点缺点那什么是集合?集合和数组的区别是什么?集合的好处和... 查看详情

java泛型:泛型类泛型接口和泛型方法

原文出自:https://segmentfault.com/a/1190000002646193泛型类publicclassContainer<K,V>{privateKkey;privateVvalue;publicContainer(Kk,Vv){key=k;value=v;}publicKgetKey(){returnkey;}publicvoidsetKey(Kkey){thi 查看详情

java泛型:泛型类泛型接口和泛型方法

根据《Java编程思想(第4版)》中的描述,泛型出现的动机在于:有许多原因促成了泛型的出现,而最引人注意的一个原因,就是为了创建容器类。泛型类容器类应该算得上最具重用性的类库之一。先来看一个没有泛型的情况下... 查看详情

kotlin基础知识汇总(知识与实践相结合)

2个月的时间总算把Kotlin的基础知识写完了,下面咱们看看具体内容:学习Kotlin的必要性【Kotlin初学者】为什么要学Kotlin 【Kotlin初学者】打牢基础的重要性运行环境【Kotlin初学者】AndroidStudio运行main函数报错解决基础知识... 查看详情

java集合框架--学习目标&集合概念&collection体系集合&collection接口

1.学习目标集合的概念Collection接口List接口与实现类泛型和工具类Set接口与实现类Map接口与实现类2.集合的概念2.1概念:对象的容器,定义了对多个对象进行操作的常用方法。可以实现数组的功能。2.2集合与数组的区别:数... 查看详情

快速上手kotlin接口抽象类及泛型(代码片段)

接口定义    kotlin规定所有的接口属性和函数实现都要使用override关键字,接口中定义的函数并不需要open关键字修饰,他们默认就是open的代码展示:packagecom.wustyq.kotlinstudyinterfaceMovablevarmaxSpeed:Intvarwheels:Intfunmove(movabl... 查看详情

java泛型知识点:泛型类泛型接口和泛型方法

有许多原因促成了泛型的出现,而最引人注意的一个原因,就是为了创建容器类。泛型类容器类应该算得上最具重用性的类库之一。先来看一个没有泛型的情况下的容器类如何定义:publicclassContainer{privateStringkey;privateStringvalue;pub... 查看详情

c#笔记(十四)——接口泛型

接口与泛型1.接口的定义:访问修饰符interface接口名{成员}2.接口是一个抽象的该年,目的在于子类实现它3.接口通常用来定义不同类之间的统一的标准4.接口的成员:包括方法、属性、事件、索引、不能有字段5.接口成员不能加修... 查看详情

kotlin学习

KotlinKotlin的变量、函数、类型Kotlin的变量、函数和类型构造器、final、静态属性和静态方法、常量、数组和集合、可见性修饰符Kotlin里那些不是这么写的构造器、函数简化、字符串、数组和集合、条件控制Kotlin里那些更方便的高... 查看详情

kotlin学习笔记-----接口(代码片段)

面向对象-----接口Kotlin中的接口和Java中的接口一样,都是使用interface关键字修饰interfaceAnimalfuneat()?classCat:Animaloverridefuneat()println("猫吃鱼")?classDog:Animaloverridefuneat()println("狗吃肉")  查看详情

kotlin学习与实践fun函数

通过例子来学习如何高效的在Kotlin中定义使用函数。1、命名参数、默认参数、顶层函数、扩展函数*展示几种创建集合类的方法和扩展的简单操作集合类的方法funcreateCollection(){valset=hashSetOf(1,12,26)println("hashSetOf-->${set.javaClass}")va... 查看详情