接口
fun main() {
val im = IM(2)
println(im.back())
}
//kotlin接口可以定义属性,不过很少使用
interface IFCallBack {
val a:Int
var b:Int
fun back() : String
}
//实现里面属性和方法都需要加override关键字
//接口是var,实现不能是val,反之是可以的
class IM(override val a: Int) : IFCallBack {
override var b:Int = 4
override fun back(): String {
return (a + b).toString()
}
}
抽象类
fun main() {
val main = MainActivity()
main.initView()
}
class MainActivity : BasActivity(name = "main"){
override fun onCreate() {
}
public override fun initView() {
super.initView()
}
}
//抽象类规则与java一致。单继承多实现
abstract class BasActivity (name:String) {
//抽象方法
abstract fun onCreate()
//子类可以覆盖重写的方法需要加open
protected open fun initView() {
}
}
泛型类
fun main() {
val arr = Arr("abc")
arr.pri(12)
val arr2 = Arr("dfd")
arr2.pri(false)
}
//泛型类和java写法一样
class Arr<T : String>(item:T) {
private var sub = item
fun <R> pri(r:R) : T {
println("$sub $r")
return sub
}
}
vararg可变长参数
fun main() {
add(1, 2, 3)
}
//vararg表示可变长参数,相当于java的...
fun add(vararg item:Int) {
item.forEach {
println(it)
}
}
out协变,in逆变
//out协变关键字表示泛型只能作为方法返回值
interface Production<out T> {
fun product() : T
}
//in逆变关键字表示泛型只能作为方法入参
interface Consumer<in T> {
fun consumer(item:T)
}
//无关键字泛型既能为方法入参也能为方法返回值
interface ProductionConsumer<T> {
fun productConsumer(item:T) : T
}
//食物类
open class Food
//快餐食物类
open class FastFood : Food()
//汉堡类
class Burger : FastFood()
//食物商店
class FoodStore : Production<Food> {
override fun product(): Food {
println("create Food")
return Food()
}
}
//快餐食物商店
class FastFoodStore : Production<FastFood> {
override fun product(): FastFood {
println("create FastFood")
return FastFood()
}
}
//汉堡商店
class BurgerStore : Production<Burger> {
override fun product(): Burger {
println("create Burger")
return Burger()
}
}
//食物消费者
class EveryBody : Consumer<Food> {
override fun consumer(item: Food) {
println("eat Food")
}
}
//快餐消费者
class FastPeople : Consumer<FastFood> {
override fun consumer(item: FastFood) {
println("eat FastFood")
}
}
//汉堡消费者
class BurgerPeople : Consumer<Burger> {
override fun consumer(item: Burger) {
println("eat Burger")
}
}
fun main() {
val food1:Production<Food> = FoodStore()
food1.product()//create Food
//使用out关键字的泛型,子类泛型对象可以赋值给父类泛型对象
val food2:Production<Food> = FastFoodStore()
food2.product()//create FastFood
val food3:Production<Food> = BurgerStore()
food3.product()//create Burger
//使用in关键字的泛型,父类泛型对象可以赋值给子类泛型对象
val people1:Consumer<Burger> = EveryBody()
people1.consumer(Burger())//eat Food
val people2:Consumer<Burger> = FastPeople()
people2.consumer(Burger())//eat FastFood
val people3:Consumer<Burger> = BurgerPeople()
people3.consumer(Burger())//eat Burger
}
reified关键字
open class Young {
open val name:String? = null
}
class Boy(override val name: String) : Young()
class Girl(override val name:String) : Young()
//通过reified配合inline内联保存泛型对象类型使用
//内联使用inline关键字使得代码编译时期将执行语句替换到相应位置,少创建对象,优化内存
//下面方法编译后将不存在,语句直接合并至main方法中
inline fun<reified T> getT(item:Young, createT:()->T) : T {
//传入一个对象,若是T直接返回,否则重新创建一个T对象返回
return if (item is T) {
item
} else{
createT()
}
}
fun main() {
val boy1 = getT(Girl("Girl1")) {
Boy("Boy1")
}
println(boy1.name)
val boy2 = getT(Boy("Boy2")) {
Boy("Boy3")
}
println(boy2.name)
}
扩展函数
fun main() {
println("abc".addPlus())
println("abc".addMoreOne(3))
12.pri()
"aaa".pri()
"sss".anyPri().addPlus().anyPri()
val strNull:String? = null
strNull.priNotNull("is Null")
"The People's Republic of China".numVowels.anyPri()
}
//扩展函数,给任意一个类添加自定义函数,后续该类对象可以直接使用
//扩展函数原理是编译阶段生成一个方法,将前置对象以入参形式传入方法中
//String后面加上plus字符串,单行语句可简写为fun String.addPlus() = this + "plus"
fun String.addPlus() : String {
return this + "plus"
}
//字符串后面添加num个1
fun String.addMoreOne(num:Int) = this + "1".repeat(num)
//Any父类设置一种打印方法
private fun Any.pri() : Any {
println(this)
return this
}
//字符串子类覆盖Any类的方法
private fun String.pri() : String {
println("字符串$this")
return this
}
//泛型扩展函数,灵活度更高,apply,let等标准函数的源码都是这个写出来的
private fun <T> T.anyPri() : T {
println(this)
return this
}
//可空类型的扩展函数
private fun String?.priNotNull(default:String) = println(this ?: default)
//扩展属性
//定义String的属性表示元音字母的数量
private val String.numVowels
get() = count {"aeiou".contains(it)}
infix关键字
fun main() {
val ic = InfixClass()
ic add 5
ic pri "abc"
}
//infix关键字使用在有单个参数的类函数与扩展函数中,调用时可省略点和括号
class InfixClass {
private val num = 20
infix fun add(other:Int) = println(num + other)
}
infix fun<T> InfixClass.pri(t:T) = println(t)
Kotlin导包别名
package com.kevin.kotlin_test.ext
//定义取集合中的随机元素方法
fun <T> Iterable<T>.randomItem() : T = this.shuffled().first()
package com.kevin.kotlin_test
//导包使用,通过as关键字能取别名使用
import com.kevin.kotlin_test.ext.randomItem as rand
fun main() {
val list = listOf(1, 2, 3, 4, 5)
println(list.rand())
}
泛型匿名扩展函数
fun main() {
val rm = Rm().rm {
a = "is A"
b = "is B"
}
println(rm.toString())
}
//泛型匿名扩展函数,很多标准函数的原理
//入参是泛型匿名扩展函数的好处是能将对象本身以this隐式传入方法体中(带接收者的函数字面量)
private fun <T> T.rm(block: T.() -> Unit) : T {
block()
return this
}
class Rm {
var a:String? = null
var b:String? = null
override fun toString(): String {
return "a=$a b=$b"
}
}
DSL-变换函数
//函数式编程范式(DSL):主要依赖于高阶函数(以函数为入参或出参)返回的数据
//Kotlin支持面向对象编程范式和函数式编程范式混用
//函数式编程主要由三类函数构成:变换transform,过滤filter,合并combine。
//每类函数都是针对集合数据类型设计,目标是产生一个最终结果,可以通过链式构建多个简单函数解决复杂的计算
//函数式编程的设计理念是不可变数据的副本在链上函数间传递
fun main() {
//变换函数会遍历集合内容,用一个以值参形式传入变换器函数,变换每一个元素,然后返回已修改的元素的集合给链上其他函数使用
//map函数返回的集合中元素个数与原函数必须一样,但元素类型可以不一样
val list = listOf(1, 2, 3, 4, 5)
val list2 = list.map {
it + 2
}.map {
it - 3
}.map {
"num = $it"
}
println(list)
println(list2)
println(list2[0]::class.simpleName)
//flatMap函数将操作多个集合之后进行合并返回合并后的集合
val flatList = listOf(listOf(1, 2, 3), listOf("4", 5, 6)).flatMap {
it - 2
}
println(flatList)
flatList.forEach {
println(it::class.simpleName)
}
//对象数据操作,返回元素的引用地址不变
val dataList = listOf(DslData("DOG"), DslData("Cat"))
val afterDataList = dataList.map {
it.name = it.name + "S"
it
}
println(dataList)
println(afterDataList)
}
class DslData(var name:String)
DSL-过滤函数
fun main() {
//过滤函数 filter函数遍历集合,把使方法体中返回true的元素加入新集合
val listFilter = listOf(1, 2, 3, 4, 5, 6).filter {
it >= 4
}
println(listFilter)
}
DSL-合并函数
fun main() {
val list1 = listOf("A", "B", "C")
val list2 = listOf(1, 2, 3)
//合并函数zip能将两个list合并成Pair元素集合,通过toMap方法可转成Map使用
//合并的两个函数size不同的话生成的集合不会包含超出部分元素
val zip = list1.zip(list2).toMap()
println(zip)
//fold函数表示对一个集合遍历处理,每次循环记录上次的处理结果提供给下一次循环
//例如下面例子,对1,2,3,4四个数字分别进行平方后相加
//fold函数入参表示记录的默认值,acc表示上次记录值,i表示当前循环中的元素
val result = listOf(1, 2, 3, 4).fold(0) { acc, i ->
acc + i*i
}
println(result)
}
DSL的算法示例
fun main() {
//将二维list集合中带red的元素重新加入到一个新集合中
val list = listOf(listOf("red apple", "green apple", "blue apple")
, listOf("red fish", "blue fish")
, listOf("yellow banana", "green banana"))
val result = list.flatMap { it -> it.filter { it.contains("red") } }
println(result)
//求100以内的质数集合
//until表示从一个数到最后一个数前一位循环遍历,..是包含最后一位数
val result100 = (2..100).toList().filter { item ->
//none表示没有一个符合的返回true
//每个元素对2到它前一位遍历取模,若取出的结果数组中没有一个为0则代表此数为质数
(2 until item).map { num -> item % num }.none { it == 0 }
}
println(result100)
//取1到100以内前10个质数,take函数取集合前几位的元素
println((2..100).toList().filter { it.isZhiShu() }.take(10))
//generateSequence方法生成Sequence集合
//在未知集合的size,定义集合的初始元素与下一个元素的生成规则,通过take生成满足条件的Sequence集合
//不使用take直接使用toList会导致线程挂起
println(generateSequence(2) { it + 1 }.filter { it.isZhiShu() }.take(10).toList())
}
fun Int.isZhiShu() :Boolean {
(2 until this).map {
if (this % it == 0) {
return false
}
}
return true
}
java与kotlin互相调用
package com.kevin.kotlin_test.ext;
import com.kevin.kotlin_test.JavaData;
import com.kevin.kotlin_test.Kotlin;
import java.io.IOException;
import kotlin.jvm.functions.Function1;
public class Test {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String kotlinClass() {
System.out.println(Kotlin.javaFun());
System.out.println(new JavaData().name);
System.out.println(JavaData.MAX_NUM);
JavaData.companionFun();
try {
Kotlin.javaException();
} catch (IOException e) {
e.printStackTrace();
}
//java提供0个入参到22个入参的方法类型从Function0到Function22
Function1<String, String> funData = Kotlin.getFunData();
System.out.println(funData.invoke("KEVIN"));
return null;
}
}
//java调用全局函数变量可以使用的类名重命名
@file:JvmName("Kotlin")
package com.kevin.kotlin_test
import com.kevin.kotlin_test.ext.Test
import java.io.IOException
fun main() {
val test = Test()
//java中带有get和set前缀的public方法可直接简化使用
test.name = "kevin"
test.age = 22
println(test.name)
println(test.age)
//调用java方法要注意使用空安全符
test.kotlinClass()?.toString()
}
//java可以使用重载函数调用
@JvmOverloads
fun javaFun(a:String="a", b:String="b") = "aaa"
//java中可以捕获指定异常
@Throws(IOException::class)
fun javaException(){
throw IOException()
}
class JavaData {
//java可以直接使用kotlin的set和get方式调用
@JvmField
val name:String = "java"
companion object {
const val MAX_NUM = 10
//java中直接通过类名调用伴生对象函数
@JvmStatic
fun companionFun() = println("companionFun")
}
}
//java中调用函数属性
val funData = { it:String ->
it.toLowerCase().capitalize()
}