Kotlin入门(Android开发)基础知识汇总(三)之函数运用
1.函数的基本用法//java@Overridepublic void onCreate(Bundle savedInstanceState) {...}//Kotlinoverride fun onCreate(savedInstanceState: Bundle?) {...}<1>使用小写“override”在同一行表达重载操作;<2>...
1.函数的基本用法
//java
@Override
public void onCreate(Bundle savedInstanceState) {
...
}
//Kotlin
override fun onCreate(savedInstanceState: Bundle?) {
...
}
<1>使用小写“override”在同一行表达重载操作;
<2>默认函数是公开的,忽略关键字“public”;
<3>不存在关键字void,若无返回参数,则不用特别说明;
<4>用关键字“fun”表示这里是函数定义;
<5>使用“变量名称:变量类型”声明输入参数的格式;
<6>如果某个变量为空,需要在变量类型后面加个问号“?”。
1.1输入参数的格式
函数既可以没有输入参数,也可以没有输出参数;或者只有输入参数;输入参数可空
//没有输入参数,没有输出参数
fun getDinnerEmpty() {
tv_result.text = ""
}
//只有输入参数
fun getDinnerInput(egg:Int, leek:Double, water:String, shell:Float) {
tv_result.text = ""
}
//输入参数存在空值
fun getDinnerCanNull(egg:Int, leek:Double, water:String?, shell:Float)
{
tv_result.text = ""
}
1.2 输出参数的格式
fun main():Int//输入参数后加“:数据类型”
开发者不声明任何返回参数时,Kotlin默认返回一个Unit类型的对象。
fun getDinnerUnit():Unit {
tv_result.text = ""
}
//只有输出参数
fun getDinnerOutput():String {
var dinner:String = "巧妇难为无米之炊"
return dinner
}
//同时具备输入参数和输出参数
fun getDinnerFull(egg:Int, leek:Double, water:String?, shell:Float):String {
var dinner = "横看成岭侧成峰..."
return dinner
}
1.3输入参数的变化
默认参数
fun getFourBigDefault(general:String, first:String="造纸", second:String="印刷术",
third:String="火药", fourth:String="指南针"):String {
var answer:String = "$general:$first:$second:$third:$fourth"
return answer
}
//如果调用参数没有给出某参数的具体值,系统就自动对该参数赋予默认值
btn_input_default.setOnClickListener {
tv_four_answer.text= getFourBigDefault("中国古代四大发明")
}
命名参数
btn_input_part.setOnClickListener {
tv_four_answer.text=getFourBigDefault("中国古代四大发明","蔡伦发明的造纸") }
//如果不需要某参数默认值,只需调用“变量名="***"”
btn_input_name.setOnClickListener {
tv_four_answer.text=getFourBigDefault("中国古代四大发明",second="活字印刷") }
可变参数
在Java体系中采取“Object... args”,Kotlin中使用关键字vararg,表示其后的参数个数是不确定的,以可变字符串为例,则表示为“vararg args: String?”。
fun getFourBigVararg(general:String, first:String="造纸术", second:String="印刷术", third:String="火药", fourth:String="指南针", vararg otherArray: String?):String {
var answer:String = "$general:$first:$second:$third:$fourth"
//循环取出可变参数包含的所有字段
for (item in otherArray) {
answer = "$answer$item"
}
return answer
}
btn_param_vararg.setOnClickListener {
tv_four_answer.text = if (isOdd) getFourBigVararg("古代四大发明") else getFourBigVararg("古代的七大发明","造纸术","印刷术","火药","指南针","丝绸","瓷器","茶叶")
isOdd = !isOdd
}
可变数组参数
fun getFourBigVararg(general:String, first:String="造纸术", second:String="印刷术", third:String="火药", fourth:String="指南针", vararg otherArray: Array<String>):String {
var answer:String = "$general:$first:$second:$third:$fourth"
//先遍历每个数组
for (array in otherArray) {
//再遍历数组元素
for (item in array) {
answer = "$answer:$item"
}
}
}
btn_param_array.setOnClickListener {
tv_four_answer.text = if (isOdd) getFourBigArray("古代的四大发明") else getFourBigArray("古代的N大发明","造纸术","印刷术","火药","指南针",arrayOf("丝绸","瓷器","茶叶"),arrayOf("国画","中医","武术"))
isOdd = !isOdd
}
2.特殊函数
2.1泛型函数
定义泛型函数时,得在函数名称前添加“<T>”,表示以T声明的参数(包括输入参数和输出参数),其参数类型必须在参数调用时指定。
fun <T> appendString(tag:String, vararg otherInfo: T?):String {
...}
var count = 0
btn_vararg_generic.setOnClickListener {
tv_function_result.text = when (count%3) {
0 -> appendString<String>("古代的四大发明","造纸术","印刷术","火药","指南针")
1 -> appendString<Int>("小于10的素数",2,3,5,7)
else -> appendString<Double>("烧钱的日子",5.20,6.18,11.11,12.12)
}
count++
2.2内联函数
如果参数类型都是继承自某种类型,那么允许在定义函数时指定从这个基类泛化开,凡是继承自该基类的子类,都可以作为输入参数进行函数调用,反之无法调用函数。举个例子,Int、Float和Double都继承自Number类,但是假如定义一个输入参数形式为setArrayNumber(array:Array<Number>)的函数,它并不接受Array<Int>或者Array<Double>的入参。如果要让该方法同时接收整型和双精度的数组入参,就得指定泛型变量T来自于基类Number,即将“<T>”或者“<reified T : Number>”,同时在fun前面添加关键字inline,表示该函数属于内联函数。
//该函数既不接收Array<Int>,也不接收Array<Double>
fun setArrayNumber(array:Array<Number>) {
var str:String = "数组元素依次排列:"
for (item in array) {
str = str + item.toString() + ", "
}
tv_function_result.text = str
}
//只有内联函数才可以被具体化
inline fun <reified T : Number> setArrayStr(array:Array<T>) {
var str:String = "数组元素依次排列:"
for (item in array) {
str = str + item.toString() + ", "
}
tv_function_result.text = str
}
var int_array:Array<Int> = arrayOf(1, 2, 3)
var float_array:Array<Float> = arrayOf(1.0f, 2.0f, 3.0f)
var double_array:Array<Double> = arrayOf(11.11, 22.22, 33.33)
btn_generic_number.setOnClickListener {
when (count%3) {
0 -> setArrayStr<Int>(int_array)
1 -> setArrayStr<Float>(float_array)
else -> setArrayStr<Double>(double_array)
}
count++
}
//btn_generic_number.setOnClickListener { setArrayNumber(int_array) }//报错
2.3简化函数
如果一个函数的表达式比较简单,一两行代码就可以搞定,那么使用等号代替大括号。示例:
fun factorial(n:Int):Int {
if (n <= 1) n
else n*factorial(n-1)
}
//简化函数
fun factorial(n:Int):Int = if (n <= 1) n else n*factorial(n-1)
2.4尾递归函数
函数末尾的返回值重复调用了自身函数,该函数叫尾递归函数。此时要在fun前加上关键字tailrec,
//尾递归函数会使编译器自动优化递归,即用循环方式代替递归,从而避免栈溢出的情况
tailrec fun findFixPoint(x: Double = 1.0): Double
= if (x == Math.cos(x)) x else findFixPoint(Math.cos(x))
2.5 高阶函数
A函数作为B函数的输入参数,那么B函数称为高阶函数。
//greater方法作为参数传入,且其含有2个输入参数,返回值为布尔值
//如果第1个参数大于第2个参数,就认为greater返回true,否则返回false
fun <T> maxCustom(array: Array<T>, greater: (T, T) -> Boolean): T? {
var max: T? = null
for (item in array)
if (max == null || greater(item, max))
max = item
return max
}
var string_array:Array<String> = arrayOf("How", "do", "you", "do", "I'm", "Fine")
btn_function_higher.setOnClickListener {
tv_function_result.text = when (count%4) {
0 -> "字符串数组默认最大值为${string_array.max()}"
1 -> "字符串数组按长度比较的最大值为${maxCustom<String>
(string_array, { a, b -> a.length > b.length })}"
2-> " 字符串数组的默认最大值为${maxCustom(string_array, { a, b -> a > b })}"
else -> "字符串数组去掉空格再比较长度的最大值为${maxCustom (string_array, { a, b -
> a.trim().length > b.trim().length })}"
}
count++;
}
“{ a, b -> a.length > b.length }”这是Lambda表达式的匿名函数写法,前半部分表示函数的输入参数,后半部分表示函数体。按照规范的函数写法是这样:
fun anonymous(a:String, b:String):Boolean {
var result:Boolean = a.length > b.length
return result
}
3.增强系统函数
3.1扩展函数
允许开发者给系统类补写新的方法,而无须另外编写额外的工具类。
比如系统的Array类除了sort,max等方法,我们可以给它添加一个扩展函数swap
fun Array<Int>.swap(pos1: Int, pos2: Int) {
val tmp = this[pos1] //this表示数组自身
this[pos1] = this[pos2]
this[pos2] = tmp
}
//扩展函数结合泛型函数能更好地扩展函数的功能
fun <T> Array<T>.swap(pos1: T, pos2: T) {
val tmp = this[pos1]
this[pos1] = this[pos2]
this[pos2] = tmp
}
val array:Array<Double> = arrayOf(1.0, 2.0, 3.0, 4.0, 5.0)
btn_function_extend.setOnClickListener {
array.swap(0, 3)
}
3.2 扩展高阶函数
给2.5提到的高阶函数maxCustom添加扩展函数功能。该函数的目的是求数组元素的最大值,因此不妨加到Array<T>数组中去
fun <T> Array<T>.maxCustomize(greater: (T, T) -> Boolean): T? {
var max: T? = null
for (item in this)
if (max == null || greater(item, max))
max = item
return max
}
string_array.maxCustomize({ a, b -> a.length > b.length })//调用
3.3 日期时间函数
Kotlin无须书写专门的DateUtil工具类,直接改写Date类的扩展函数即可,下面是几个Date的扩展函数函数
//返回的日期时间格式形如 2017-10-01 10:00:00
fun Date.getNowDateTime(): String {
val sdf = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
return sdf.format(this)
}
//只返回日期字符串
fun Date.getNowDate(): String {
val sdf = SimpleDateFormat("yyyy-MM-dd")
return sdf.format(this)
}
//只返回时间字符串
fun Date.getNowTime(): String {
val sdf = SimpleDateFormat("HH:mm:ss")
return sdf.format(this)
}
//返回详细的时间字符串,具体到毫秒
fun Date.getNowTimeDetail(): String {
val sdf = SimpleDateFormat("HH:mm:ss.SSS")
return sdf.format(this)
}
//返回开发者指定格式的日期时间字符串
fun Date.getFormatTime(format: String=""): String {
var ft: String = format
val sdf = if (!ft.isEmpty()) SimpleDateFormat(ft)
else SimpleDateFormat("yyyyMMddHHmmss")
return sdf.format(this)
}
Date().getNowDate()//调用例子
3.4 单例对象
Kotlin使用对象关键字“Object”加以修饰,并称之为单例对象,相当于Java的工具类。
下面是采取单例对象改写的日期时间工具代码:
object DateUtil {
//声明一个日期时间的属性
//返回的日期时间格式形如2017-10-01 10:00:00
val nowDateTime: String
get() {
//外部访问DateUtil.nowDateTime时,会自动调用nowDateTime附属的get方法得到它的值
val sdf = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
return sdf.format(Date())
}
val nowDate: String
get() {
val sdf = SimpleDateFormat("yyyy-MM-dd")
return sdf.format(Date())
}
...
}
DateUtil.nowDateTime//调用
更多推荐

所有评论(0)