函数定义使用关键字fun,参数格式为:参数:类型
funsum(a:Int,b:Int):Int{returna+b}funprint(a:Int,b:Int):Unit{println(a+b)}可变长参数函数函数的变长参数可以用vararg关键字进行标识:
funvars(varargv:Int){for(vtinv){print(vt)}}//测试funmain(args:Array
//测试funmain(args:Array
var<标识符>:<类型>=<初始化值>不可变变量定义:val关键字,只能赋值一次的变量(类似Java中final修饰的变量)
val<标识符>:<类型>=<初始化值>常量与变量都可以没有初始化值,但是在引用前必须初始化
//类型后面加表示可为空varage:String="23"//抛出空指针异常valages=age!!.toInt()//不做处理返回nullvalages1=age.toInt()//age为空返回-1valages2=age.toInt():-1类型检测及自动类型转换重点:做过类型检测之后,obj会自动被系统转换为String类型我们可以使用is运算符检测一个表达式是否某类型的一个实例(类似于Java中的instanceof关键字)。
fungetStringLength(obj:Any):Int{if(objisString){//做过类型判断以后,obj会被系统自动转换为String类型returnobj.length}//在这里还有一种方法,与Java中instanceof不同,使用!is//if(obj!isString){////XXX//}//这里的obj仍然是Any类型的引用returnnull}或者
fungetStringLength(obj:Any):Int{if(obj!isString)returnnull//在这个分支中,`obj`的类型会被自动转换为`String`returnobj.length}甚至还可以
fungetStringLength(obj:Any):Int{//在`&&`运算符的右侧,`obj`的类型会被自动转换为`String`if(objisString&&obj.length>0)returnobj.lengthreturnnull}区间区间表达式由具有操作符形式..的rangeTo函数辅以in和!in形成。
区间是为任何可比较类型定义的,但对于整型原生类型,它有一个优化的实现。以下是使用区间的一些示例:
for(iin1..4)print(i)//输出“1234”for(iin4..1)print(i)//什么都不输出if(iin1..10){//等同于1<=i&&i<=10println(i)}//使用step指定步长for(iin1..4step2)print(i)//输出“13”for(iin4downTo1step2)print(i)//输出“42”//使用until函数排除结束元素for(iin1until10){//iin[1,10)排除了10println(i)}kotlin基本数据类型比较2个数字Kotlin中没有基础数据类型,只有封装的数字类型,你每定义的一个变量,其实Kotlin帮你封装了一个对象,这样可以保证不会出现空指针。数字类型也一样,所以在比较两个数字的时候,就有比较数据大小和比较两个对象是否相同的区别了。
在Kotlin中,三个等号===表示比较对象地址,两个==表示比较两个值大小。
由于不同的表示方式,较小类型并不是较大类型的子类型,较小的类型不能隐式转换为较大的类型。这意味着在不进行显式转换的情况下我们不能把Byte型值赋给一个Int变量。
valb:Byte=1//OK,字面值是静态检测的vali:Int=b//错误vali:Int=b.toInt()//OK位操作符对于Int和Long类型,还有一系列的位操作符可以使用,分别是:
shl(bits)–左移位(Java’s<<)shr(bits)–右移位(Java’s>>)ushr(bits)–无符号右移位(Java’s>>>)and(bits)–与or(bits)–或xor(bits)–异或inv()–反向字符的使用fundecimalDigitValue(c:Char):Int{if(c!in'0'..'9')throwIllegalArgumentException("Outofrange")returnc.toInt()-'0'.toInt()//显式转换为数字}数组数组的创建两种方式:一种是使用函数arrayOf();另外一种是使用工厂函数。如下所示,我们分别是两种方式创建了两个数组:
funmain(args:Array
funmain(args:Array
funmain(args:Array
valc=if(condition)aelsebwhen条件表达式when表达式类似java的switch语句。具体用法可以参考如下几个示例。
when(x){1,2->print("x==1")3->print("x==2")else->{//这里可以写成代码块print("x不是123")}}//使用in操作when(x){in1..10->print("xisintherange")invalidNumbers->print("xisvalid")!in10..20->print("xisoutsidetherange")else->print("noneoftheabove")}//使用is操作funhasPrefix(x:Any)=when(x){isString->x.startsWith("prefix")else->false}//可以用来取代ifelse链when{x.isOdd()->print("xisodd")x.isEven()->print("xiseven")else->print("xisfunny")}//in操作funmain(args:Array
在Kotlin中任何表达式都可以用标签(label)来标记。标签的格式为标识符后跟@符号,例如:abc@、fooBar@都是有效的标签。要为一个表达式加标签,我们只要在其前加标签即可。
loop@for(iin1..100){//……}现在,我们可以用标签限制break或者continue:loop@for(iin1..100){for(jin1..100){if(……)break@loop}}标签限制的break跳转到刚好位于该标签指定的循环后面的执行点。continue继续标签指定的循环的下一次迭代。
标签处返回Kotlin有函数字面量、局部函数和对象表达式。因此Kotlin的函数可以被嵌套。标签限制的return允许我们从外层函数返回。最重要的一个用途就是从lambda表达式中返回。回想一下我们这么写的时候:
funfoo(){ints.forEach{if(it==0)returnprint(it)}}这个return表达式从最直接包围它的函数即foo中返回。(注意,这种非局部的返回只支持传给内联函数的lambda表达式。)如果我们需要从lambda表达式中返回,我们必须给它加标签并用以限制return。
funfoo(){ints.forEachlit@{if(it==0)return@litprint(it)}}现在,它只会从lambda表达式中返回。通常情况下使用隐式标签更方便。该标签与接受该lambda的函数同名。
funfoo(){ints.forEach{if(it==0)return@forEachprint(it)}}或者,我们用一个匿名函数替代lambda表达式。匿名函数内部的return语句将从该匿名函数自身返回
funfoo(){ints.forEach(fun(value:Int){if(value==0)returnprint(value)})}当要返一个回值的时候,解析器优先选用标签限制的return,即return@a1意为"从标签@a返回1",而不是"返回一个标签标注的表达式(@a1)"。
Koltin中的类可以有一个主构造器,以及一个或多个次构造器,主构造器是类头部的一部分,位于类名称之后:
注意:无需对抽象类或抽象成员标注open注解。
openclassBase{openfunf(){}}abstractclassDerived:Base(){overrideabstractfunf()}嵌套类我们可以把类嵌套在其他类中,看以下实例:
classOuter{//外部类privatevalbar:Int=1classNested{//嵌套类funfoo()=2}}funmain(args:Array
内部类会带有一个对外部类的对象的引用,所以内部类可以访问外部类成员属性和成员函数。
使用对象表达式来创建匿名内部类:
classTest{varv="成员属性"funsetInterFace(test:TestInterFace){test.test()}}/***定义接口*/interfaceTestInterFace{funtest()}funmain(args:Array
classModifier:类属性修饰符,标示类本身特性。abstract//抽象类final//类不可继承,默认属性enum//枚举类open//类可继承,类默认是final的annotation//注解类accessModifier:访问权限修饰符private//仅在同一个文件中可见protected//同一个文件中或子类可见public//所有调用的地方都可见internal//同一个模块中可见实例
classExample//从Any隐式继承注意:Any不是java.lang.Object。
如果一个类要被继承,可以使用open关键字进行修饰。
openclassBase(p:Int)//定义基类classDerived(p:Int):Base(p)构造函数:子类有主构造函数:如果子类有主构造函数,则基类必须在主构造函数中立即初始化。
openclassPerson(varname:String,varage:Int){//基类}classStudent(name:String,age:Int,varno:String,varscore:Int):Person(name,age){}//测试funmain(args:Array
classStudent:Person{constructor(ctx:Context):super(ctx){}constructor(ctx:Context,attrs:AttributeSet):super(ctx,attrs){}}DEMO:
/**用户基类**/openclassPerson{openfunstudy(){//允许子类重写println("我毕业了")}}/**子类继承Person类**/classStudent:Person(){overridefunstudy(){//重写方法println("我在读大学")}}funmain(args:Array
interfaceFoo{valcount:Int}classBar1(overridevalcount:Int):FooclassBar2:Foo{overridevarcount:Int=0}kotlin接口Kotlin接口与Java8类似,使用interface关键字定义接口,允许方法有默认实现,且可以实现多个接口。
interfaceMyInterface{funbar()//未实现funfoo(){//已实现//可选的方法体println("foo")}}classChild:MyInterface{overridefunbar(){//方法体}}接口中的属性接口中的属性只能是抽象的,不允许初始化值,接口不会保存属性值,实现接口时,必须重写属性:
interfaceMyInterface{varname:String//name属性,抽象的funbar()funfoo(){//可选的方法体println("foo")}}classChild:MyInterface{overridevarname:String="w3cschool"//重写属性overridefunbar(){//方法体println("bar")}}funmain(args:Array
interfaceA{funfoo(){print("A")}//已实现funbar()//未实现,没有方法体,是抽象的}interfaceB{funfoo(){print("B")}//已实现funbar(){print("bar")}//已实现}classC:A{overridefunbar(){print("bar")}//重写}classD:A,B{overridefunfoo(){super.foo()super.foo()}overridefunbar(){super.bar()}}funmain(args:Array
扩展是一种静态行为,对被扩展的类代码本身不会造成任何影响。
扩展函数扩展函数可以在已有类中添加新的方法,不会对原类做修改,扩展函数定义形式:
funreceiverType.functionName(params){body}receiverType:表示函数的接收者,也就是函数扩展的对象functionName:扩展函数的名称params:扩展函数的参数,可以为NULL以下实例扩展User类:
classUser(varname:String)/**扩展函数**/funUser.Print(){print("用户名$name")}funmain(arg:Array
//扩展函数swap,调换不同位置的值funMutableList
Kotlin可以创建一个只包含数据的类,关键字为data:dataclassUser(valname:String,valage:Int)
dataclassUser(valname:String,valage:Int)
funmain(args:Array
}输出结果为:
User(name=Jack,age=1)User(name=Jack,age=2)
创建类的实例时我们需要指定类型参数:valbox:Box
枚举类最基本的用法是实现一个类型安全的枚举。
枚举常量用逗号分隔,每个枚举常量都是一个对象。
enumclassColor{RED,BLACK,BLUE,GREEN,WHITE}枚举初始化每一个枚举都是枚举类的实例,它们可以被初始化:
classMyClass{companionobjectFactory{funcreate():MyClass=MyClass()}}该伴生对象的成员可通过只使用类名作为限定符来调用:
valinstance=MyClass.create()可以省略伴生对象的名称,在这种情况下将使用名称Companion:
classMyClass{companionobject{}}valx=MyClass.Companion其自身所用的类的名称(不是另一个名称的限定符)可用作对该类的伴生对象(无论是否具名)的引用:
classMyClass1{companionobjectNamed{}}valx=MyClass1classMyClass2{companionobject{}}valy=MyClass2请注意,即使伴生对象的成员看起来像其他语言的静态成员,在运行时他们仍然是真实对象的实例成员,而且,例如还可以实现接口:
companionobject{@JvmStaticfuntypeOf(type:String):NodeType{returnvalues().firstOrNull{it.type==type}}}Kotlin函数let函数首先let()的定义是这样的,默认当前这个对象作为闭包的it参数,返回值是函数里面最后一行,或者指定return
fun
funtestLet():Int{//fun
fun
funtestApply(){//fun
fun
funtestWith(){//fun