Kotlin学习笔记——接口抽象类泛型扩展集合操作符与Java互操作性单例
Posted 迷月星辰
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Kotlin学习笔记——接口抽象类泛型扩展集合操作符与Java互操作性单例相关的知识,希望对你有一定的参考价值。
注:编码工具为IntelliJ
目录
接口
接口默认是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懒汉式单例
以上是关于Kotlin学习笔记——接口抽象类泛型扩展集合操作符与Java互操作性单例的主要内容,如果未能解决你的问题,请参考以下文章