Kotlin就是一门可以运行在 JAVA虚拟机,Android,浏览器上的静态语言,它与Java100%兼容,如果你对Java非常熟悉,那么你就会发现Kotlin除了自己的标题库之外,大多任然使用经典的Java 集合框架。
学习目标
1. 学会使用 Kotlin
2. 熟悉Java生态
3. 了解一些特性背后的实现
var与val 的区别
var为可变变量,val相当于只读变量,如同java 中的final 一样,val 创建时必须被初始化。
1.认识基本类型
2.初步认识类及其相关概念
3.认识区间和数组
var a: Boolean=true
var b: Boolean=false
a为参数
var a: Int =8
var a: Int =0xFF
Float类型后面必须加F
NaN /不是数
val f1: Float =8.0F
val Positive: Float = Float.POSITIVE_INFINITY 正无穷
val Negative Float.NEGATIVE_INFINITY 负无穷
int anInt = 5
Integer anInteger = 5
在Kotlin 里面,Int实际是 int与Integer的合体,在必要的时候,编译器会自动帮我们进行分辨。
不可隐式转换
不能直接像Java里一样,将整型赋给 Long,在Kotlin 里,需要显示调用toLong()方法
val anInt : Int =5
val aLong : Long = abInt.toLong()
== 比较内容,即类似Java 的equals
=== 比较对象是否相同
//字符串模板 $
val a: Int = 1
val b: Int = 2
println("" + a + "+" + b + "=" + (a + b))
println("$a+$b=${a+b}")
如果想在字符串中添加双引号,需要添加转义字符
Petterp “123”
var string:String="Petterp \"123\""
需要打印 $ 符号
var money:String="1000"
println("$$money")
多行字符串,回车直接可以换行,trimIndent()去除字符串左边为空的位置,这里面无法使用转义
var raw:String="""
123
456
""".trimIndent()
println(raw)
//一个继承的例子
/*open相当于打开,允许被继承
主构造函数不能包含任何的代码。初始化的代码可以放到以 init 关键字作为前缀的初始化(initializerblocks)中。
在实例初始化期间,初始化块按照它们出现在类体中的顺序执行,与属性初始化器交织在一起:*/
//constructor 主构造函数
class demo1 constructor(a: String, b: String) : Demo(a, b)
class demo2 constructor(a: String, b: String) : Demo(a, b)
open class Demo (a: String,b: String) {
init {
//获取类的名字
println("${this.javaClass.simpleName} $a $b")
}
}
fun main(args: Array<String>) {
var dd1: demo2 = demo2("a", "b")
}
open 覆盖方法也需要加
override 子类覆盖时需要加
java 代码
public class MyClass {
public static void main(String[] a){
System.out.println(demo().length());
}
public static String demo(){
return null;
}
}
Kotlin 代码
fun demo(): String? {
//如果加了 ?,编译器就会允许返回null,否则直接报错
return null
}
fun main(args: Array<String>) {
//?的意思是,如果为空,则执行前半句,否则执行后半句打印长度
println(demo()?.length)
val a: String? = "123"
//!! 告诉编译器允许编译器忽略空类型安全
println(a!!.length)
}
//父类强转为子类测试
//继承关系,Chaid继承自Parent
java
public class Test {
public static void main(String[] args) {
Parent parent=new Parent();
((Chaid) parent).pp();
}
}
Kotlin
fun main(args: Array<String>) {
//父类强转为子类测试
val parent: Parent = Parent()
//如果parent转换失败,则返回null,程序而不会崩溃
val chaid: Chaid? = parent as? Chaid
//此时打印即为null
println(chaid)
}
fun main(args: Array<String>) {
val range:IntRange=0..1024 //[0,1024]
val ranege_exclusive:IntRange=0 until 1024 //[0,1024)
val range_min:IntRange= 0..-1
//判断是不是空
println(range_min.isEmpty())
//判断是否包含1024
println(ranege_exclusive.contains(1024))
//写法不同,contains 内部也是用的下面这种方法
println(1024 in range)
//迭代--相当于输出range数组
for (i in range){
print("$i,")
}
}
val arrayOfInt: IntArray = intArrayOf(1, 3, 5)
val arrayOfChar: CharArray = charArrayOf('H', 'e', 'l', 'l', 'o')
val arrayOfString: Array<String> = arrayOf("Petterp", "p")
fun main(args: Array<String>) {
//for迭代
for (int in arrayOfInt) {
println(int)
}
//返回[0,2)区间的元素
println(arrayOfString.slice(0 until 2))
//使用分隔符创建一个字符串
println(arrayOfChar.joinToString(""))
//将指定数组中的字符转换为字符串
println(String(arrayOfChar))
//打印类的全名
println(Kotlin2::class.java.name)
//打印类名区间
println(Kotlin2::class.java.simpleName.slice(0 until 2))
//基本类型转换
val hello:Long= arrayOfChar.size.toLong()
println(hello)
}
class Kotlin2 {
}
val data: String = "Petterp"
val data2 = data
//类型推导,编译器已经知道它的类型是 Int
val data3 = 1
fun main(args: Array<String>) {
println(data)
println(data2)
println(data3)
}
现在添加 const
const val data: String = "Petterp"
const val data2 = data
//类型推导,编译器已经知道它的类型是 Int
val data3 = 1
fun main(args: Array<String>) {
println(data)
println(data2)
println(data3)
}
所以这就是编译器常量的作用。编译器常量的引用都是直接指明该变量的值
//函数写法
fun Demo1(a: Int): Int {
return a
}
//当函数返回一个表达式的值是,可以使用一下方式
fun Demo2(a: Int) = a
//匿名函数,需要赋值给一个函数变量
val k = fun(a: Int): Int {
return a
}
fun main(args: Array<String>) {
println(Demo1(100))
println(Demo2(200))
println(k(300))
}
注意事项
举例
val sum{a:Int,b:Int -> a+b}
调用
sum(1,2)
sum.invoke(1,2)
//Lambda
//原始写法
args.forEach ({ println(it) })
//对于函数来说,如果最后一个参数是Lambda表达式,小括号可以移到外面
args.forEach(){ println(it) }
//如果小括号里什么都没有,可以删掉小括号
args.forEach { println(it)}
//如果传入的这个函数和需要接收的Lambda表达式类型一样,那么进一步简化
args.forEach (::println)
写法与普通函数完全一致
class A {
//简短写法,没有返回值类型的情况下
fun say(name: String) = println("Hello $name")
fun phone(phone:String):String{
return phone
}
}
// 加修饰的为属性,b只是普通的一个构造方法参数
class A(val a: Int, b: Int) {
var b = 0
}
class B{
//val 修饰的 不可变 无set方法
val demo:Int=0
/* set(value) {
}*/
var demo2:Int=0
set(value) {
println(demo2)
field = value
}
}
class X
class A(val a: Int, b: Int) {
var b = 0
//laterinit 延迟初始化
lateinit var c: String
lateinit var d: X
val e: X by lazy {
println("Start X")
X()
}
var cc: String? = null //不推荐这种写法
}
//使用operator关键字可以重载基本运算符,比如下面的plus函数加上operator,就相当于基本运算中的 +
//运算符重载要求与运算符的函数名对应,比如要重载加法,函数名就必须是 plus
class Complex(var real:Int,var imaginzry:Int){
operator fun plus(other:Complex):Complex{
return Complex(real+other.real,imaginzry+other.imaginzry)
}
operator fun plus(other: Int):Complex{
return Complex(real+other,imaginzry)
}
operator fun plus(other: Any):Int{
return real.toInt()
}
override fun toString(): String {
return "$real+$imaginzry"
}
}
class Book{
//infix 中指表达式,不用点括号去调用
infix fun on(any:Any):Boolean{
return false
}
}
class Desk
fun main(args: Array<String>) {
val c1=Complex(3,4)
val c2=Complex(1,2)
println(c1+c2)
println(c1+5)
println(c1+"Petterp")
//-name <Name>
//in 表示有这个元素返回1 否则返回-1
if ("-name" in args){
println(args[args.indexOf("-name")+1])
}
}
//infix(中缀表达式) 定义的函数不必动过.xx() 的形式调用,而是可以通过函数名(不必写括号) 调用。这种写法在Dsl 中比较常见,在代码中慎用,影响可读性
class Book{
//infix
infix fun on(any:Any):Boolean{
return false
}
}
class Desk
fun main(args: Array<String>) {
if(Book() on Desk()){
}
}
val x=if(b<0) 0 else b
val x=if(b<0) 0 //错误,赋值时,分支必须完备
fun main(args: Array<String>) {
val x=99
val b=when(x){
in 1..100 -> 10
!in 1..100 -> 20
args[0].toInt() -> 30
else -> x
}
when(x){
in 1..100 -> println("ok")
else -> println("no")
}
// val mode=when{
// args.isNotEmpty()&& args[0]=="1" ->1
// else ->0
// }
println(b)
}
fun main(args: Array<String>) {
for((i,value) in args.withIndex()){
println("$i -> $value")
}
for(i in args.withIndex()){
println("${i.index} -> ${i.value}")
}
}
val a=try {
100/10
}catch (e:Exception){
0
}
//注意下面的寫法finaly还是会先执行,最后才是 return
fun P(): Int {
//try 表达式
return try {
100 / 10
} catch (e: Exception) {
0
} finally {
println("我先打印")
}
//这样写的话,参数的位置就不会产生影响
fun main(args: Array<String>) {
sum(b=1,a=2)
}
fun sum(a: Int, b: Int) {
println("a=$a b=$b")
}
fun main(vararg: Array<String>) {
sum(1, 2, 3, 4, b = "B")
}
fun sum(vararg a: Int, b: String) {
a.forEach(::println)
println(b)
}
fun main(vararg: Array<String>) {
sum(1, 2, 3, 4, b = "B")
//Spread Operator,只支持Array
val array= intArrayOf(1,3,4,5)
sum(*array,b="B")
}
fun sum(vararg a: Int, b: String) {
a.forEach(::println)
println(b)
}
fun main(vararg: Array<String>) {
//调用者未传值,使用的是默认值
sum(b="B")
sum(1,"B")
}
//如果有个函数经常使用一个值,那么在其声明的时候就可以指定这个值
fun sum(a: Int = 0, b: String) {
println("a=$a b=$b")
}
interface A {
fun Print()
}
//接口继承
interface A1 : A {
//也可以定义一个变量,这里实际相当于方法,但是无法有set,get方法
var a: Int
fun ko() {
println(a)
}
}
class TestA(override var a: Int) : A1 {
override fun Print() {
println("Petterp")
}
}
fun main() {
val test = TestA(1)
test.Print()
test.ko()
}
interface P1
interface P2 : P1
abstract class A {
//打印出类名
fun Print() = println(javaClass.simpleName)
}
class B : A(), P2
fun main() {
//不可以这样用,因为没有子类继承
// val a = A
//关系可以这样来写
val p1: P1 = B()
val p2: P2 = B()
val a: A = B()
val b: B = B()
b.Print()
}
class D:A() , B ,C
//继承与子类重写父类的Demo
abstract class Person(open val age: Int) {
abstract fun work()
}
class MaNong(age: Int) : Person(age) {
//重写属性
override val age:Int
get() = 0
override fun work() {
println("我是碼農")
}
}
class Doctor(age: Int) : Person(age) {
override fun work() {
println("我是醫生")
}
}
fun main() {
val manong = MaNong(20)
val doctor = Doctor(100)
println(manong.age)
println(doctor.age)
}
class Manager(driver:Driver):Driver by driver
//接口代理的Demo
interface AA{
fun Print1()
}
interface BB{
fun Print2()
}
class Car:AA{
override fun Print1() {
println("AA")
}
}
class Bar:BB{
override fun Print2() {
println("BB")
}
}
//
//class AB:AA,BB{
// override fun Print1() {
// TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
// }
//
// override fun Print2() {
// TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
// }
//
//}
//by 接口代理
class SendWill(val aa:AA,val bb:BB):AA by aa,BB by bb
fun main() {
val aa=Car()
val bb=Bar()
val send=SendWill(aa,bb)
send.Print1()
send.Print2()
}
super <[父类 (接口) 名 ]>.[方法名]([参数列表]
Demo
interface A {
fun setT() = "接口A"
}
interface B {
fun setT() = "接口B"
}
abstract class C {
open fun setT() = "抽象类C"
}
class Demo(val a: Int) : A, B, C() {
override fun setT(): String {
return when (a) {
1 -> super<A>.setT()
2 -> super<B>.setT()
3 -> super<C>.setT()
else -> ""
}
}
}
fun main() {
println(Demo(1).setT())
println(Demo(2).setT())
}
Koltin--
interface A {
fun a1()
}
abstract class C
object KotlinDan : C(), A {
override fun a1() {
println("Kotlin")
}
}
Java--
public class Kotlin_java {
public static void main(String[] args) {
//引用Kotlin代码
KotlinDan.INSTANCE.a1();
//在java里面
JavaDan.inter.Ag();
}
}
//java中的简易单例例子
class JavaDan{
static JavaDan inter=new JavaDan();
private JavaDan(){}
void Ag(){
System.out.println("Java");
}
}
Kotlin--
class Demo private constructor(val value:Double){
//伴生对象
companion object {
@JvmStatic
fun A(double: Double): Demo {
return Demo(double)
}
@JvmField
val TAG:String="Petterp"
}
}
fun main() {
println(Demo.A(1.1).value)
}
Java--
public class KotlinJava {
public static void main(String[] args) {
//java代码,未添加 @JvmStataic 与 JvmField
Demo demo = Demo.Companion.A(1.1);
String tag = Demo.Companion.getTAG();
//添加后
Demo demo1 = Demo.A(1.1);
String tag1=Demo.TAG;
}
}
class A{
fun a():Int{
return 0
}
fun a(int: Int):Int{
return int
}
//方法重载与返回值无关
/* fun a():String{
}*/
}
fun main() {
val a=A().a()
val a2=A().a(123)
}
Kotlin--
class A {
// fun a():Int{
// return 0
// }
// fun a(int: Int):Int{
// return int
// }
//使用具名参数替代上面的重载方法
@JvmOverloads
fun a(int: Int = 0): Int {
return int
}
}
fun main() {
val a = A().a()
val a2 = A().a(123)
}
Java调用时--
public class KotlinJava {
public static void main(String[] args) {
A a=new A();
//在Kotlin代码上添加 @JvmOverloads 就可以让java识别具名参数
a.a();
a.a(123);
}
}
Java代码中的一个Bug
public class Bug {
public static void main(String[] args) {
List<Integer> list=new ArrayList<>();
list.add(1);
list.add(2);
list.add(10);
list.add(20);
System.out.println(list);
//异常,数组越界
list.remove(10);
list.remove(2);
}
}
在Kotlin代码中
fun main() {
val list = ArrayList<Int>()
list.add(1)
list.add(2)
list.add(10)
list.add(20)
println(list)
list.removeAt(10)
list.remove(2)
}
fun X.y():Z {...}
val X.m 注意扩展属性不能初始化,类似接口属性
operator fun String.times(int: Int):String{
val stringBuilder=StringBuilder()
for (i in 0 until int){
stringBuilder.append(this)
}
return stringBuilder.toString()
}
val String.op:String
get() = "123"
fun main() {
println("abc".times(16))
//扩展方法前加了operator,重载运算符
println("abc"*16)
println("abc".op)
}
java调用
public class A {
public static void main(String[] args) {
System.out.println(Kotlin2Kt.times("abc",16));
System.out.println(Kotlin2Kt.getOp("Petterp"));
}
}
val/var <property name>: <Type> by <experession>
//翻译 property-属性 type-类型 experssion-函数调用
// Demo--
class A{
val p1:String by lazy {
"123"
}
//属性代理,实际调用getValue
val p2 by X()
//需要实现setValue
var p3 by X()
}
class X{
private var value: String? =null
operator fun getValue(thisRef:Any?,property:KProperty<*>):String{
return value?:""
}
operator fun setValue(thisRef: Any?,property: KProperty<*>,string: String){
this.value=string
}
}
fun main() {
val a=A()
println(a.p1)
println(a.p2)
//此时为空,因为未设置值
println(a.p3)
a.p3="123"
println(a.p3)
}
//加了data 之后,自动实现各种方法,可查看字节码发现
data class A(val id:Int,val name:String)
class ComponentX{
//手动实现component1()
operator fun component1():String{
return "PP"
}
operator fun component2():Int{
return 0
}
}
fun main() {
println(A(1,"Petterp"))
val (a,b)=ComponentX()
println("a=$a,b=$b")
//打印结果
/*A(id=1, name=Petterp)
a=PP,b=0*/
}
allOpen noArg 配置方法
class A {
var int:Int = 5
//加了inner 为非静态内部类
inner class A1 {
var int:Int = 10
fun Print(){
//内部类的变量
println(int)
//外部变量
println(this@A.int)
}
}
}
interface OnclickListener {
fun onclick()
}
class View {
var onclickListener: OnclickListener? = null
}
open class A
fun main() {
val view=View()
view.onclickListener=object : A(),OnclickListener{
override fun onclick() {
}
}
}
//枚举类也是有构造方法的,我们可以在它的构造方法中传入参数
enum class LogLevel(val id:Int){
A(1),B(2),C(3),D(4),E(5) ;
//需要分号隔开
fun getTag():String{
return "$id,$name"
}
override fun toString(): String {
return "$name,$ordinal"
}
}
//LogLevel 更像是 LogLevel2的语法糖
//它们两个是等价的
class LogLevel2(val id:Int) private constructor(){
//伴生对象写法
companion object {
val A=LogLevel2(1)
val B=LogLevel2(2)
val C=LogLevel2(3)
val D=LogLevel2(4)
val E=LogLevel2(5)
}
constructor(i: Int) : this()
}
fun main() {
println("${LogLevel.A},${LogLevel.A.ordinal}")
println(LogLevel.A.getTag())
//遍历枚举,重写了toString()方法
LogLevel.values().map(::println)
//返回"A"的实例
println(LogLevel.valueOf("A"))
}
//在以下Demo中,这是一个音乐播放Demo
//需要不同指令及不需要参数的地方我们可以用枚举实现,而那些需要不同指令参数的地方我们用枚举就无法实现了
//sealed的子类只能继承在与Sealed同一个文件当中,或者作为它的内部类
sealed class PlayerCmd {
class Play(val yrl: String, val postition: Long = 0) : PlayerCmd()
class Seek(val postition: Long) : PlayerCmd()
object Pause : PlayerCmd()
object Resume : PlayerCmd()
object Stop : PlayerCmd()
}
enum class PlayerState{
IDLE,PAUSE,PLAYING
}
fun main(args: Array<String>) {
//包级函数引用
args.forEach(::println)
//类引用
val helloWorld = Hello::world
// args.filter(String::isNotEmpty)
//调用者引用方法
args.forEach(PdfPrinter()::println)
//Demo1
println(demo("k",::getRest))
//Demo2
demo2(Hello()::world)
}
class Hello {
fun world(){
println("123")
}
}
class PdfPrinter {
fun println(any: Any) {
kotlin.io.println(any)
}
}
fun getRest(s1:String):String="Petterp $s1"
fun demo(a: String, method: (s1: String) -> String): String = method(a)
fun demo2(methoud2:()->Unit)=methoud2()
val list = listOf(1, 3, 4, 5, 6, 7, 8)
val newList=ArrayList<Int>()
list.forEach {
newList.add(it*2)
}
newList.forEach(::println)
val list = listOf(1, 3, 4, 5, 6, 7, 8)
val newList = list.map { it * 2 + 3 }
newList.forEach(::println)
fun main() {
.flatMap { intRange ->
intRange.map { intElement ->
"No.$intElement"
}
}.forEach(::println)
//简写
list.flatMap {
it.map { "No.$it" }
}.forEach(::println)
}
fun main() {
//遍历0..6的阶乘
(0..6).map(::factorial).forEach(::println)
//加初始值5 结果: 879
println((0..6).map(::factorial).fold(5){acc, i ->acc+i})
//加上psotion
println((0..6).map(::factorial).foldIndexed(StringBuilder()){postion,acc, i ->acc.append("$i-$postion,")})
//更改返回类型 结果 1,1,2,6,24,120,720,
println((0..6).map(::factorial).fold(StringBuilder()){acc, i -> acc.append("$i,") })
//倒序
println((0..6).map(::factorial).foldRight(StringBuilder()){i,acc -> acc.append(i).append(",") })
//字符串连接
println((0..6).joinToString(","))
}
//求阶乘
fun factorial(n:Int):Int{
if (n==0){
return 1
}
return (1..n).reduce { acc, i -> acc*i}
}
fun main() {
val list = listOf(
1..20,
6..100,
200..220
)
//求和 结果:9655
println(list.flatMap { it }.reduce { acc, i -> acc + i })
}
val list = listOf(
1,3,2
)
//传入的表达式值为true就保留
println(list.filter { it%2==0 })
//满足条件的保留,并有他们的位置
println(list.filterIndexed{index, i -> i%2==1 })
val list = listOf(
1,3,2
)
//从第一个元素开始,只返回符合的元素,遇到不符合停止
println(list.takeWhile { it%2==1 })
//从最后一个元素开始,一直取到不符合的就返回前面的元素
println(list.takeLastWhile { it%2==0})
//返回最后一个元素到指定元素位置的列表,不包含指定位置元素
println(list.takeLast(4))
//返回第一个一个元素到指定元素位置的列表,不包含指定位置元素
println(list.take(4))
//参数是个方法,返回值是一个布尔类型,为真返回对象T,否则返回null
println(list.takeIf { it.size>6 })
data class Person(val name: String, val age: Int) {
fun work() {
println("我是$name")
}
}
fun main() {
findPerson()?.let {
it.work()
println(it.age)
}
//apply相当于一个扩展方法
findPerson()?.apply {
work()
println(age)
}
BufferedReader(FileReader("A.txt")).use {
var line:String?
while (true){
line=it.readLine()?:break
println(line)
}
}
// val br=BufferedReader(FileReader("hello.txt")).readLine()
}
fun findPerson(): Person? {
return null
}
尾递归指的是函数调用自己之后没有任何操作,也就是一个函数中所有递归形式的调用都出现在函数的末尾。尾递归可以使用 tailrec 关键字优化
data class ListNode(val value:Int,var next:ListNode?=null)
tailrec fun findListNode(head:ListNode?,value:Int):ListNode?{
head?:return null
if (head.value==value) return head
return findListNode(head.next,value)
}
fun main() {
val Max_Node_Court=1000000
val head=ListNode(0)
var p=head
for (i in 1..Max_Node_Court){
p.next= ListNode(i)
p=p.next!!
}
println(findListNode(head,Max_Node_Court-2)?.value)
}
fun factorial(n:Long):Long{
return n* factorial(n-1)
}
data class TreeNode(val value:Int){
var left:TreeNode?=null
var right:TreeNode?=null
}
fun findTreNode(root:TreeNode?,value: Int):TreeNode?{
root?:return null
if (root.value==value) return root
return findTreNode(root.left,value)?:return findTreNode(root.right,value)
}
val String="HelloWord"
//Lambda 返回一个无参函数
fun makeFun():() -> Unit{
var count=0
return fun (){
println(++count)
}
}
fun main(args: Array<String>) {
// val x= makeFun()
// x()
// x()
val add5= add(5)
println(add5(2))
for (i in fibonac()){
if (i>100) break
println(i)
}
}
fun fibonac():Iterable<Long>{
var first=0L
var second=1L
return Iterable {
object :LongIterator(){
override fun hasNext()=true
override fun nextLong(): Long {
val result=second
second+=first
first=second-first
return result
}
}
}
}
//Demo2
//简写
fun add(x:Int)=fun (y:Int)=x+y
//完整
fun add2(x: Int):(Int)->Int{
return fun (y:Int):Int{
return x+y
}
}
val add5={i:Int -> i+5} //f(g(x))
val mulyiplyBy2={i:Int ->i*2} // m(x)=f(g(x))
fun main(args: Array<String>) {
println(mulyiplyBy2(add5(8))) //(5+8)*2
val k= add5 andThen mulyiplyBy2
println(k(8))
}
/*P1,P2 表示参数值,R表示返回值
addThen为扩展方法
infix中缀表达式
Function<P1,P2> p1为参数类型,P2为返回值类型
*/
infix fun <P1,P2,R > Function1<P1,P2>.andThen(function: Function1<P2,R>):Function1<P1,R>{
return fun (p1:P1):R{
//返回了一个函数,函数里面又把function这个参数调用了一遍
//调用的时候又把自己调用了一遍,把自己的返回值传给function
return function.invoke(this.invoke(p1))
}
}
infix fun <P1,P2,R> Function1<P1,P2>.compose(function: Function1<P2,R>):Function1<P1,R>{
return fun (p1:P1):R
{
return function.invoke(this.invoke(p1))
}
}
//由多参数变换为单参数的变化
fun Test(a: Int): (String) -> (Int) -> Boolean {
return fun(b: String): (c: Int) -> Boolean {
return fun(c: Int): Boolean {
return true
}
}
}
fun log(tag: String, target: OutputStream, message: Any?) {
target.write("[$tag] $message\n".toByteArray())
}
//柯里化
fun log2(tag: String)
= fun(target: OutputStream)
= fun(message: Any?)
= target.write("[$tag] $message\n".toByteArray())
fun main() {
log("benny",System.out,"Heelo2wor")
log2("Petterp")(System.out)("Demo")
::log.curried()("Petterp")(System.out)("Demo")
}
fun <P1,P2,P3,R> Function3<P1,P2,P3,R>.curried()
=fun(p1:P1)=fun (p2:P2)=fun (p3:P3)=this(p1,p2,p3)
val test=fun(name:String,love:String):String{
return "${name}爱$love"
}
fun <P1,P2,R> Function2<P1,P2,R>.partial1(p1:P1)=fun(p2:P2)=this(p1,p2)
fun <P1,P2,R> Function2<P1,P2,R>.partial2(p2:P2)=fun (p1:P1)=this(p1,p2)
fun main() {
val t= test.partial1("Petterp")
println(t("写Bug"))
val t2= test.partial2("改Bug")
println(t2("Petterp"))
}
Kotlin在编译的时候,会增加一个函数调用,会对参数类型,返回值类型进行是否为null的检查
因为Java里面并没有空安全类型,所以可能会出现平台类型的问题,这时候就需要我们开发者自己明白需要使用的参数是否可以为null
在开发Java代码的时候,可以通过注解的方式来弥补这一点
在java里并没有这种函数,它在编译的时候,会为Kotlin生成一个类,这个类包含了所有包级函数,在java看来,这些都只是静态方法,所以在java调用的时候,按照静态按方法调用即可
扩展方法只是增加了一个 Receiver 作为参数
如果一个参数带有默认参数,Java实际是看不见的
支持Jpa注解,如 @Entity
支持 Spring注解,如 @Component
ArrayList<out String>
java 的List-> Kotlin的List<*>
//定义一个接口
interface SimpleInter {
fun test()
val number: Int
}
//open表示允许继承,在Kotlin中,类和方法之间默认不允许继承和重写(不包括抽象类)
open class SimpleClass{
open fun put()
}
//实现接口中的参数
class Test1(override val number: Int) :SimpleClass(),SimpleInter{
//接口方法
override fun test() {
}
//重写父类方法
override fun openTest() {
super.openTest()
}
}
//在kotlin中,默认会为参数添加set,get方法,如果需要自定义,按照以下方式写即可
class ClassTest1(override val number: Int) : SimpleInter {
override fun test() {
}
var money = number
get() {
return field
}
set(value) {
field = value
}
}
val number=Test1::number
//属性调用
val classTest=ClassTest1(123)
val money=classTest::money
money.set(456)
class Book{
}
//定义Book类的扩展方法
fun Book.noBook(){
}
//也可以定义扩展属性
// Backing Field
//扩展成员变量无法存储状态,因为不存在field
var Book.money: Int
get() {
return this.saveInt
}
set(value) {
this.saveInt = value
}
//接口可以定义变量
interface Guy {
var moneyLeft: Double
get() {
return 0.0
}
set(value) {
}
}
class Book{
}
fun main() {
val book=Book()
if (book is Book){
//安全的类型转换
println((book as? Book)?.javaClass?.name)
}
}
var b: String = "asdasd"
val c: Int = 15
字符串比较,
==,===
== 比较内容是否相等
=== 比较对象是否相等
//it代表当前数组下标
var intArray = IntArray(3) { it +3}
//获取长度
println(intArray.size)
//打印数组
println(intArray.contentToString())
//打印数组
val dd= arrayOf(1,2,3)
println("${dd[1]},${dd[2]}")
//按数组下标打印
val ss= intArrayOf(1,2,3,4);
for (i in ss.indices){
println(ss[i])
}
//数组遍历
for (d in dd){
print(d)
}
//函数式写法
dd.forEach { d->
println(d)
}
//如果使用默认it,则可以省略 d->
dd.forEach { println(it)}
/* 判断是否在一个数组内 */
if (5 in dd){
println("在数组dd内")
}
if (5 !in dd){
println("不在数组dd内")
}
//表示创建了一个1-10的闭区间
val intRange=1..10
val charRange='a'..'z'
val longRange=1L..1000L
//创建开区间
val intRangeExclusive=1 until 10 //[1,10)
//倒序区间
val intRangeReverse=10 downTo 1 //[10,9,...,1]
//区间添加步长
val intRange1=1..10 step 3 // [1,4,7,9,10]
//打印区间
println(intRange1.joinToString())
//不可变List,不可添加或删除
val intList: List<Int> = listOf(1,2,3)
//可变List
val intList2: MutableList<Int> = mutableListOf(1, 2, 3, 4)
//不可变map
val map:Map<String,Any> = mapOf("name" to "petterp","ts" to 123)
val mutilMap:Map<String,Any> = mutableMapOf("name" to "petterp","Ts" to 123)
//直接创建Java中的List
val intList = ArrayList<Int>()
val stringList = ArrayList<String>()
val intList = ArrayList<Int>()
//List的写入 等价于 add
for (i in 0..10){
intList+=i
}
//删除某个元素,等价于 remove
intList.remove(100)
//修改某个元素的值 类似于 set(0,101)
intList[0]=101
val maps = HashMap<String, String>(10)
//添加某个元素
maps+=("key1" to "test")
println(maps.toString())
//修改某个元素
maps["key1"]="petterp"
println(maps.toString())
Any 相当于Object
如果我们查看 Kotlin中的 ArrayList,会发现
其中 Typealias 相当与为类型起新名称
我们在上面Map中用到了 ”“ to ""
Var pair=""
val map = HashMap<String, String>()
val pair = "key" to "petterp"
val pair2 = Pair("Hello", "Petterp")
//获取键
val key = pair.first
//获取值
val second = pair.second
//puts如map
map += pair
map += pair2
println("$key , $second")
fun main() {
val map = HashMap<String, Int>()
val kotlinBook = "Kotlin核心技术" to 88
val AndroidBook = Pair("Android艺术探索", 66)
println("${kotlinBook.first} , ${kotlinBook.second}")
map += kotlinBook
map += AndroidBook
println("解构开始\n\n")
/*解构声明*/
//参考https://www.kotlincn.net/docs/reference/multi-declarations.html
//将一个对象解构为多个变量
println("解构对象")
val (x, y) = Book("Kotlin核心技术", 88)
println(x)
println(y)
println("\n 遍历map")
//使用解构遍历map,可能是最好的方式
for ((name, value) in map) {
println("$name , $value")
}
println("\n 忽略某些解构")
//如果你不想解构某些变量,则通过 _ 标志
for ((name, _) in map)
println(name)
println("\n lambda中使用解构")
//使用解构返回一个新的map,key不变,返回的只是value的改变
val maps = map.mapValues { (name, value) -> "5" }
println(map.toString())
println(maps.toString())
println("\n 函数中使用解构")
//从函数中返回两个变量
val (name, money) = funcation()
println("$name , $money")
//从函数中返回两个变量
}
data class Book(var name: String, var money: Int)
fun funcation(): no1.Book {
println("经历了一波操作")
return no1.Book("Android艺术探索", 99)
}
Kotlin核心技术 , 88
解构开始
解构对象
Kotlin核心技术
88
遍历map
Kotlin核心技术 , 88
Android艺术探索 , 66
忽略某些解构
Kotlin核心技术
Android艺术探索
lambda中使用解构
{Kotlin核心技术=88, Android艺术探索=66}
{Kotlin核心技术=5, Android艺术探索=5}
函数中使用解构
经历了一波操作
Android艺术探索 , 99
/**
* Nothing has no instances. You can use Nothing to represent "a value that never exists": for example,
* if a function has the return type of Nothing, it means that it never returns (always throws an exception).
*/
//*没有实例。您可以使用Nothing来表示“一个永不存在的值”:例如,*如果函数的返回类型为Nothing,则表示该函数永不返回(总是引发异常)。
public class Nothing private constructor()
fun test(type: String) =
when (type) {
"key1" -> "条件1"
"key2" -> "条件2"
else -> caseDefault()
}
/** 一个报错的逻辑,为了便于编译器识别,返回类型依然为String
* 如果是其他情况,相应返回类型需要更改方可便于编译器,否则相应的异常每个方法都需要手动添加 */
private fun caseDefault(): String {
throw RuntimeException("123")
}
使用 Nothing 优化这段代码
fun test(type: String) =
when (type) {
"key1" -> "条件1"
"key2" -> "条件2"
else -> doNothing()
}
private fun doNothing(message: String="Nothing is all"): Nothing {
throw RuntimeException(message)
}
fun main() {
//函数引用的几种方法
val x = Test::pp
val x1: (Test, String) -> String = Test::pp
val x2: (Test, String) -> String = x
val x3: Function2<Test, String, String> = Test::pp
}
class Test {
fun pp(name: String): String {
return name
}
}
fun main(){
val x1: (Test, String) -> String = Test::pp
println(Test().pp2(x1, 123))
}
class Test(){
fun pp(name: String): String {
return name
}
fun pp2(name: (Test, String) -> String, value: Int): String {
return "${name(Test(), "132")} , $value"
}
}
fun main(){
//默认参数
default("Android")
//如果你的默认参数为第一个,此时就需要声明显示类型
default(name = "Android")
}
fun default(name: String, money: Int = 9) {
}
fun main(){
//变长参数
channels("Asd", "Asd")
}
fun channels(vararg args: String) {
println(args.joinToString())
}
fun main(){
var (a, b, c) = test1()
println("$a , $b ,$c")
}
fun test1(): Triple<Int, String, String> {
return Triple(123, "asd", "asdfa");
}
fun main() {
val res: String = readLine()!!
if (res.isEmpty()) {
throw RuntimeException("不可为null")
}
val operations = mapOf(
"+" to ::plus,
"-" to ::minus,
"*" to ::times,
"/" to ::div
)
when {
"+" in res -> {
val (a, b) = res.split("+")
println(operations["+"]?.invoke(a.toInt(), b.toInt()))
}
"-" in res -> {
}
"*" in res -> {
}
"/" in res -> {
}
}
}
fun plus(a: Int, b: Int): Int {
return a + b
}
fun minus(a: Int, b: Int): Int {
return a + b
}
fun times(a: Int, b: Int): Int {
return a + b
}
fun div(a: Int, b: Int): Int {
return a + b
}
fun main() {
Kang::name
Kang::money //报错
}
//加了var或者val 就相当于成员变量,全局可见,否则就只能在构造器(init块)内可见,类似于局部变量
class Kang(var name:String,money:Int)
class Kang(var name:String,money:Int){
init {
this.name=money.toString()
}
init {
println()
}
init {
println("我是Petterp")
}
}
class Kang(override var name:String, money:Int):Test(name){
init {
this.name=money.toString()
}
init {
println()
}
init {
println("我是Petterp")
}
fun void(){
}
//副构造器,同时调用了主构造器
constructor(name: String):this(name,123){
this.name=name
}
}
如果未定义主构造器,则可以直接调用其他副构造器,和java基本没有什么不同.不过这种写法并不推荐
class Test3{
constructor(name:String){
}
constructor(money:Int):this("123"){
}
}
Kotlin推荐以主构造器+默认参数的形式去写。如果要用在Java中,则加上 @JvmOverloads
class Test3 constructor(){
constructor(name:String){
}
@JvmOverloads
constructor(money:Int):this("123"){
}
}
| 可见性类型 | Java | Kotlin |
|---|---|---|
| public | 公开 | 与java相同,默认就是public |
| internal | x | 模块内可见 |
| default | 包内可见,默认 | x |
| protected | 包内及子类可见 | 类内及子类可见 |
| private | 类内可见 | 类或文件内可见 |
如果我们想避免Java直接访问到我们的代码,可以加入以下小技巧,这样当Java调用时就会因不规范而报错。
//
class Person(var age: Int, var name: String) {
var fitstName: String = ""
private set(value) {
field = name
}
}
private val rvMainActivity by lazy {
findViewById<RecyclerView>(R.id.rv_main)
}
private lateinit var recyclerView:RecyclerView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
recyclerView=findViewById(R.id.rv_main)
}
private var recyclerView:RecyclerView?=null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
recyclerView=findViewById(R.id.rv_main)
recyclerView?.adapter=RecyclerCustomAdapter(arrayListOf("123","234"))
}
用于监控属性值发生变更,类似一个观察者,当属性值被修改后往外部抛出一个变更的回调。
//使用state变量代理StateManager,从而属性更改时实现监听
class StateManager{
var state:Int by Delegates.observable(0){
property, oldValue, newValue ->
println("$oldValue->$newValue")
}
}
fun main() {
var stateManager = StateManager()
stateManager.state=4
stateManager.state=5
}
fun main(){
//属性x将它的访问器逻辑委托给了X对象
var x:Int by X()
}
//遵循getValue,setValue,如果是val,只支持getValue
class X{
operator fun getValue(nothing: Nothing?, property: KProperty<*>): Int {
return 2
}
operator fun setValue(nothing: Nothing?, property: KProperty<*>, i: Int) {
}
}
需要在使用前初始化
//返回具有 非Null参数的委托
var name:String by Delegates.notNull()
用于在属性改变发生是通知外部变化,在里面可以做一些改变,返回一个状态,如果满足条件返回true,否则false
var vetoable: Int by Delegates.vetoable(0) { property, oldValue, newValue ->
println("old-$oldValue---new-$newValue")
return@vetoable newValue == 123
}
用于在属性发生变化时调用指定的回调函数
var observable:Int by Delegates.observable(0){
property, oldValue, newValue ->
}
class PropertiesDelegate(private val path: String, private val defaultValu: String = "") {
private lateinit var url: URL
private val properties: Properties by lazy {
val prop = Properties()
url = try {
javaClass.getResourceAsStream(path).use {
prop.load(it)
}
javaClass.getResource(path)!!
} catch (e: Exception) {
try {
ClassLoader.getSystemClassLoader().getResourceAsStream(path).use {
prop.load(it)
}
ClassLoader.getSystemClassLoader().getResource(path)!!
} catch (e: Exception) {
FileInputStream(path).use {
prop.load(it)
}
URL("file://${File(path).canonicalPath}")
}
}
prop
}
operator fun getValue(thisRef: Any?, kProperty: KProperty<*>): String {
return properties.getProperty(kProperty.name, defaultValu)
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
properties.setProperty(property.name, value)
File(url.toURI()).outputStream().use {
properties.store(it, "petterp")
}
}
}
abstract class AbsProperties(path: String) {
protected val prop = PropertiesDelegate(path)
}
class Config : AbsProperties("Config.properties") {
var name by prop
}
fun main() {
val config=Config()
println(config.name)
config.name="asdasd"
println(config.name)
}
//饿汉式单例
object Singleton{
}
便于Java调用
@JvmStatic 生成静态方法
@JvmField 生成set,get
Kotlin中没有static变量,所以使用伴生对象代替静态变量。使用前需要带上 相应注解
class Test{
companion object{
fun of(){
}
}
}
class Outher{
//非静态内部类
inner class Inner{
}
//静态内部类
class staticInner{
}
}
class Outher {
//非静态内部类
inner class Inner {
}
//静态内部类
class staticInner {
object OutherObject {
var x=5
}
}
}
fun main() {
Outher.staticInner.OutherObject.x
}
fun main() {
//可继承父类或实现多个接口
//类型-交叉类型 ClassPath&Runnable(猜测)
object : ClassPath(), Runnable {
override fun run() {
}
override fun test() {
}
}
}
abstract class ClassPath {
abstract fun test()
}
data class Book(val id:Int,val money:Double){
}
| JavaBean | data class | |
|---|---|---|
| 构造方法 | 默认无参构造 | 属性作为参数 |
| 字段 | 字段私有,Getter/Setter公开 | 属性 |
| 继承性 | 可继承也可被继承 | 不可被继承 |
| Component | 无 | 相等性,解构等 |
enum class State{
A,B
}
enum class States(val id:Int){
Idle(0),Busy(1)
}
//枚举实现接口
enum class ClassPath : Runnable {
IDLE,BUSY;
override fun run() {
}
}
//为每一个枚举实现接口方法
enum class EnumOffer : Runnable {
idle {
override fun run() {
}
},
busy{
override fun run() {
}
}
override fun run() {
}
}
fun State.sout() {
println("扩展")
}
enum class State {
A, B
}
fun main() {
val s = State.B
if (s>State.A) println("ok")
}
enum class State {
A, B,C,D,E
}
fun main() {
val s = State.B
if (s in State.A..State.C) println("ok")
}
简单来说,密封类相当于一类事物的具体子分类,有明确的类型区别,子类有具体个数。在when表达式中,对密封类有优化效果
sealed class Book(val name: String)
class Android(name: String) : Book(name)
class Java(name: String, var money: Int) : Book(name)
fun main() {
list(Android("Kotlin"))
list(Java("Javaxx", 99))
}
//在条件全部满足的情况下,无需else
fun list(book: Book) = when (book) {
is Android -> println(book.name)
is Java -> println("${book.name} -- ${book.money}")
}
| 密封类 | 枚举类 | |
|---|---|---|
| 状态实现 | 子类继承 | 类实例化 |
| 状态可数 | 子类可数 | 实例可数 |
| 状态差异 | 类型差异 | 值差异 |
inline class Unit constructor(internal val data: Int) : Comparable<Unit> {
override fun compareTo(other: Unit): Int {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
}
设置:狂欢ruby1.9.2高线(1.6.13)描述:我已经相当习惯在其他一些项目中使用highline,但已经有几个月没有使用它了。现在,在Ruby1.9.2上全新安装时,它似乎不允许在同一行回答提示。所以以前我会看到类似的东西:require"highline/import"ask"Whatisyourfavoritecolor?"并得到:Whatisyourfavoritecolor?|现在我看到类似的东西:Whatisyourfavoritecolor?|竖线(|)符号是我的终端光标。知道为什么会发生这种变化吗? 最佳答案
我在我的Rails项目中使用Pow和powifygem。现在我尝试升级我的ruby版本(从1.9.3到2.0.0,我使用RVM)当我切换ruby版本、安装所有gem依赖项时,我通过运行railss并访问localhost:3000确保该应用程序正常运行以前,我通过使用pow访问http://my_app.dev来浏览我的应用程序。升级后,由于错误Bundler::RubyVersionMismatch:YourRubyversionis1.9.3,butyourGemfilespecified2.0.0,此url不起作用我尝试过的:重新创建pow应用程序重启pow服务器更新战俘
我遇到了一个非常奇怪的问题,我很难解决。在我看来,我有一个与data-remote="true"和data-method="delete"的链接。当我单击该链接时,我可以看到对我的Rails服务器的DELETE请求。返回的JS代码会更改此链接的属性,其中包括href和data-method。再次单击此链接后,我的服务器收到了对新href的请求,但使用的是旧的data-method,即使我已将其从DELETE到POST(它仍然发送一个DELETE请求)。但是,如果我刷新页面,HTML与"new"HTML相同(随返回的JS发生变化),但它实际上发送了正确的请求类型。这就是这个问题令我困惑的
我有可变数量的表格和可变数量的行,我想让它们一个接一个地显示,但如果表格不适合当前页面,请将其放在下一页,然后继续。我已将表格放入事务中,以便我可以回滚然后打印它(如果高度适合当前页面),但我如何获得表格高度?我现在有这段代码pdf.transactiondopdf.table@data,:font_size=>12,:border_style=>:grid,:horizontal_padding=>10,:vertical_padding=>3,:border_width=>2,:position=>:left,:row_colors=>["FFFFFF","DDDDDD"]pdf.
我安装了ruby、yeoman,当我运行我的项目时,出现了这个错误:Warning:Running"compass:dist"(compass)taskWarning:YouneedtohaveRubyandCompassinstalledthistasktowork.Moreinfo:https://github.com/gruUse--forcetocontinue.Use--forcetocontinue.我有进入可变session目标的路径,但它不起作用。谁能帮帮我? 最佳答案 我必须运行这个:geminstallcom
文章目录一、项目场景二、基本模块原理与调试方法分析——信源部分:三、信号处理部分和显示部分:四、基本的通信链路搭建:四、特殊模块:interpretedMATLABfunction:五、总结和坑点提醒一、项目场景 最近一个任务是使用simulink搭建一个MIMO串扰消除的链路,并用实际收到的数据进行测试,在搭建的过程中也遇到了不少的问题(当然这比vivado里面的debug好不知道多少倍)。准备趁着这个机会,先以一个很基本的通信链路对simulink基础和相关的debug方法进行总结。 在本篇中,主要记录simulink的基本原理和基本的SISO通信传输链路(QPSK方式),计划在下篇记
我不是Ruby专家,但想弄清楚发生了什么,因为我试图让指南针在节点应用程序中工作,但我的Ruby似乎坏了。打字:ruby--version让我:ruby2.1.1p76(2014-02-24revision45161)[x86_64-darwin13.0]我安装了Homebrew,之前遇到过Ruby版本的问题,但它似乎已安装并且可以正常工作。但是,当我使用gem输入请求时,出现此错误:$gem-hErrorloadingRubyGemsplugin"/Users/user_dir/.rvm/gems/ruby-2.1.1@global/gems/executable-hooks-1.3
我正在使用Rails5ApplicationController.renderer.render方法从模型中进行渲染。我需要将一些变量传递给我的布局,这是我使用locals选项完成的;如果直接访问此变量,则该变量在布局中可用,但不能通过self访问。这是我设置渲染的方式html_string=ApplicationController.renderer.render(file:"/#{template_path}/base/show",:formats=>[:pdf,:html],locals:{:@routing_form=>self,:controller_name=>contro
我正在尝试安装bootstrap-sass并收到以下错误。我试过旧版本的sass,但bundler一直在安装3.3.0。WARN:UnresolvedspecsduringGem::Specification.reset:sass(~>3.2)WARN:Clearingoutunresolvedspecs.Pleasereportabugifthiscausesproblems./Library/Ruby/Gems/2.0.0/gems/compass-0.12.2/lib/compass/sass_extensions/monkey_patches/browser_support.r
我正在尝试使用Vagrant创建我的第一个ChefRecipe,但在第一步就遇到了问题。我的Recipe的第一行是:include_recipe"apt"但是当我尝试vagrantprovision时,出现以下错误:==>default:[2014-09-21T07:15:42+00:00]WARN:MissingCookbookDependency:==>default:Recipe`apt`isnotintherun_list,andcookbook'apt'==>default:isnotadependencyofanycookbookintherun_list.Toloadth