override fun onCreate(savedInstanceState: Bundle?) {
…
}
对比区别如下:
(1)Java使用“@Override”表示该函数重载父类的方法,而Kotlin使用小写的“override”在同一行表达重载操作
(2)Java使用“public”表示该函数是公共方法,而Kotlin默认函数就是公开的,所以省略了关键字“public”
(3)Java使用“void”表示该函数没有返回参数,而Kotlin不存在关键字“void”,若无返回参数,则不用特别说明。
(4)Kotlin新增了关键字“fun”,表示这里是函数定义,其格式类似于Java的关键字“class”,而Java不存在关键字“fun”。
(5)Java声明输入参数的格式为“变量类型 变量名称”,而Kotlin声明输入参数的格式为“变量名称:变量类型”。
(6)Kotlin引入空安全机制,如果某个变量允许为空,就需要在变量类型后面加个问号“?”。
Kotlin的函数写法与Java的传统写法区别很大,刚从Java开发Android转Kotlin开发Android的朋友会不适应,但是后面你就会明白Kotlin的优势了,这也是Google为什么大力推荐的原因,好了,话不多少,实践是检验真理的唯一标准。示例代码如下:
//没有输入参数,也没有输出参数
fun getEmpty(){
tv_title.text = “空空如也”
tv_result.text = “”
}
//只有输入参数
fun getInput(egg:Int,leek:Double,water:String,shell:Float){
tv_title.text = “两个鸡蛋,一把韭菜,一些矿泉水”
tv_result.text = “”
}
//输入参数存在空值
fun getCanNull(egg:Int,leek:Double,water:String?,shell:Float){
tv_result.text = if(water!= null) “两个鸡蛋,一把韭菜,一些矿泉水” else “没有水”
tv_result.text = “”
}
代码中有三个方法,第一个没有入参没有返回参数,第二个只有入参,第三个入参中存在空值,下面用三个按钮来调用一下:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android=“http://schemas.android.com/apk/res/android”
xmlns:app=“http://schemas.android.com/apk/res-auto”
xmlns:tools=“http://schemas.android.com/tools”
android:orientation=“vertical”
android:gravity=“center_horizontal”
android:layout_width=“match_parent”
android:layout_height=“match_parent”
tools:context=“.MainActivity”>
<TextView
android:textColor=“#000”
android:id=“@+id/tv_title”
android:layout_width=“wrap_content”
android:layout_height=“wrap_content”/>
<TextView
android:textColor=“#000”
android:id=“@+id/tv_result”
android:layout_width=“wrap_content”
android:layout_height=“wrap_content”/>
<LinearLayout
android:gravity=“center”
android:layout_marginTop=“20dp”
android:layout_width=“match_parent”
android:layout_height=“wrap_content”>
<Button
android:id=“@+id/btn_one”
android:text=“One”
android:layout_width=“wrap_content”
android:layout_height=“wrap_content”/>
<Button
android:id=“@+id/btn_two”
android:text=“Two”
android:layout_width=“wrap_content”
android:layout_height=“wrap_content”/>
<Button
android:id=“@+id/btn_three”
android:text=“Three”
android:layout_width=“wrap_content”
android:layout_height=“wrap_content”/>
代码中使用
btn_one.setOnClickListener { getEmpty() }
btn_two.setOnClickListener { getInput(2,11.11,“水”,100f) }
btn_three.setOnClickListener { getCanNull(2,11.11,null,100f) }
运行效果图如下:
没有输入参数
有输入参数
输入参数有空值的
输出参数由函数,函数在Kotlin中怎么定义的呢,这个跟Java就不太一样了,代码如下:
//声明变量
var Tests:Int
//定义函数
fun Test():Int
Kotlin设计师的初衷就是把函数当成一个特殊的变量,既然函数被当作一种特殊的变量,同时每个变量都有变量类型,假如函数存在返回参数,那么自然把返回参数的类型作为该函数的变量类型,要是函数不存在返回参数,也就是Java中的返回void,Java中使用void表示不存在返回参数,而Kotlin的返回参数是一定存在的,即使开发者不声明任何返回参数,Kotlin函数也会默认返回一个Unit类型的对象,代码如下:
fun getEmpty():Unit{
tv_title.text = “空空如也”
tv_result.text = “”
}
这个Unit是代表无需返回具体的值,所以Kotlin代码中往往会省略掉,所以你写不写都可以(PS:那你说这么多废话干啥!!!),但增加Unit类型的目的是让函数定义完全符合变量定义的形式,若函数需要具体的输出对象,则一样要在函数末尾使用关键字“return”来返回参数值,代码如下:
//只有输出参数
fun getOutput():String{
tv_title.text = “空空如也”
var result:String = “汪峰”
return result
}
接下来定义一个同时包含入参和出参的函数,代码如下:
//同时具备入参和出参的函数
fun getInputAndOutput(one:String,two:String,three:String):String{
tv_title.text = "人物包括 $one $two $three "
var result:String = “三国”
return result
}
btn_one.setOnClickListener {
tv_result.text = getInputAndOutput(“刘备”,“曹操”,“孙权”)
}
效果图如下:
======================================================================
先来写一个函数
fun getFourBook(
info: String,
first: String,
second: String,
third: String,
fourth: String
): String {
var answer: String = “ i n f o 、 info 、 info、first 、 s e c o n d 、 second 、 second、third 、$fourth”
return answer
}
var isOdd = true//如果从初始赋值中能够知道变量类型,就无须显示指定该变量的类型
btn_test.setOnClickListener {
tv_result.text = if (isOdd) getFourBook(
“四大名著是:”,“《三国演义》”,
“《水浒传》”, “《红楼梦》”, “《西游记》”
) else
getFourBook(“四书五经中的四书是:”,“《大学》”, “《中庸》”, “《论语》”, “《孟子》”)
isOdd = !isOdd
}
运行效果如下
奇次数点击如下
偶次数点击如下
我这一顿操作的意义何在呢?不是说默认参数吗?请听我慢慢道来,Kotlin中引入了默认参数的概念,允许在定义函数时直接指定输入参数的默认值。如果调用函数没有给出某参数的具体指,系统就自动对该参数赋予默认值,从而免去每次都要手动赋值的麻烦,那么怎么写默认参数呢?只需在声明输入参数时在其后面加上等号及其默认值即可,如下所示:
fun getFourBook(
info: String = “四大名著是:”,
first: String = “《三国演义》”,
second: String = “《水浒传》”,
third: String = “《红楼梦》”,
fourth: String = “《西游记》”
): String {
var answer: String = “ i n f o 、 info 、 info、first 、 s e c o n d 、 second 、 second、third 、$fourth”
return answer
}
btn_test.setOnClickListener {
tv_result.text = getFourBook(“中国四大名著是:”)
}
运行效果如下:
就是这样的神奇,请注意在Java中是不能这么写的。
如果觉得参数的默认值内容不够完整,想加入新的值,比如书的作者,可以这样写:
btn_test.setOnClickListener {
tv_result.text = getFourBook(“中国四大名著是:”,“罗贯中写的《三国演义》”)
}
这一步是没有问题了,加入我要改第四本书的值呢?n难道要把前三本书的值也都写上去吗?那也太鸡肋了吧,出于这个考虑🤔,Kotlin又引进了命名函数的概念,说的是调用函数时可以指定某个参数的名称及其数值,格式如“参数名=参数值”,演示代码如下:
这个地方为什么用截图而不是直接贴代码呢,因为我觉得这个引用方式比较酷,还用蓝色标出来了。我们运行一下看看结果吧,不然就是银样镴枪头,中看不中用。
运行效果如下:
很明显,Kotlin并非浪得虚名,献丑了~
上面的参数都是固定的个数,现在说到可变参数就是随时添加,在Java中,如果不确定参数个数的话通常用“Object…args”的形式,那么Kotlin中呢?当然是新增关键字了,就是vararg,(PS:你看像不像吧var 和 arg 拼起来的单词),表示其后的参数个数是不确定的,而Kotlin会把可变参数当成是一个数组,开发者需要循环取出每个参数值进行处理,代码如下:
这个地方不贴代码,因为我希望有人能敲一边,而不是一味的复制和粘贴,那样是没有用的。
偶次数点击效果图如下
刚才我们用的时候字符串,接下来用数组来试一下
var isOdd = true
fun getFourBook(
info: String = “四书指的是:”,
first: String = “《大学》”,
second: String = “《中庸》”,
third: String = “《论语》”,
fourth: String = “《孟子》”,
vararg otherArray:Array
): String {
var answer: String = “ i n f o 、 info 、 info、first 、 s e c o n d 、 second 、 second、third 、$fourth”
//先遍历每个数组
for(array in otherArray){
//再遍历某个数组中的所有元素
for(item in array){
answer = “$answer, $item”
}
}
return answer
}
btn_test.setOnClickListener {
tv_result.text = if(isOdd) getFourBook(“四书五经中的四书指的是:”) else
getFourBook(“四书五经六艺全指什么”,“《大学》”,“《中庸》”,“《论语》”,
“《孟子》”, arrayOf(“《诗经》”,“《尚书》”,“《礼记》”,“《周易》”,“《春秋》”),
arrayOf(“《易》”,“《书》”,“《诗》”,“《礼》”,“《乐》”,“《春秋》”))
isOdd = !isOdd
}
运行效果如下:
===================================================================
我们先声明几个泛型
var int_array:Array = arrayOf(1,2,3)
var long_array:Array = arrayOf(1,2,3)
var float_array:Array = arrayOf(1.0f,2.0f,3.0f)
看起来是不是很眼熟呢?注意到尖括号内部制定了数组元素的类型,这正是泛型的写法“<>”。由“Array<变量类型>”声明而来的变量可称作泛型变量,至于等号后面的arrayOf*便是泛型函数。定义泛型函数时,需要在函数名称前面添加“”,表示以T声明的参数(包括输入参数和输出参数),其参数类型必须在函数调用时指定,代码示例如下:
//Kotlin允许定义全局函数,即函数可在单独的kt文件中定义,然后其他地方也能直接调用
fun appendString(tag:String,vararg otherInfo:T?):String{
var str:String = “$tag:”
//遍历可变参数中的泛型变量,将其转换为字符串再拼接到一起
for(item in otherInfo){
str = “ s t r str str{item.toString()},”
}
return str
}
var count = 0
btn_test.setOnClickListener {
tv_result.text = when(count%3){
0 -> appendString(“四大名著”,“《三国演义》”,
“《水浒传》”,“《红楼梦》”,“《西游记》”)
1 -> appendString(“小于10的素数”,2,3,5,7)
else -> appendString(“键盘的价格”,39.99,128.00,246.57)
}
count++
}
运行效果如下:
字符串:
整数:
双精度数
什么是内联函数呢?举个例子,Int、Float和Double都继承自Number类,但是假如定义一个输入参数形式为setArrayNumber(array:Array< Number >)的函数,它并不接受Array< Int >或者Array< Double >的入参。如果要让该方法同时接收整型和双精度的数组入参,就得指定泛型变量T来自于基类Number,即将“< T >”改为“< reified T : Number>”,同时在fun前面添加关键字inline,表示该函数属于内联函数,内联函数在编译的时候回在调用处把该函数的内部代码直接复制一份,调用多少次复制多少份,而非普通函数那样仅仅提供一个函数的访问地址。
//普通函数
fun setArrayNumber(array: Array) {
var str: String = “数组元素一次排列”
for(item in array){
str = str + item.toString() + ", "
}
tv_result.text = str
}
//只有内联函数才能被具体化 请注意,这个inline是全局的,所以不能写在函数方法里面,要写在外面
inline fun setArrayStr(array: Array){
var str:String =“数组元素依次排列”
for (item in array){
str = str + item.toString() + ", "
}
tv_result.text = str
}
上面的泛型函数兼内联函数setArrayStr在定义的时候比较麻烦,不过外部的调用方式没有发生改变,调用代码如下
var int_array:Array = arrayOf(1,2,3)
var float_array:Array = arrayOf(1.0f,2.0f,3.0f)
var double_array:Array = arrayOf(3.14,2.54,3.45)
//Kotlin进行循环调用时,要求参数类型完全匹配,所以即使Int继承自Number类,也不能调用setArrayNumber方法传送Int类型
var count = 0
btn_test.setOnClickListener {
when(count%3){
0 -> setArrayStr(int_array)
1 -> setArrayStr(float_array)
else -> setArrayStr(double_array)
}
count++
}
运行效果如下:
整数
浮点
双精度
简化函数可以用一个数学题来演示,比如 5!=5_4_3_2_1,用Kotlin代码来看
fun test(n: Int): Int {
if (n <= 1) n else n * test(n - 1)
return 0
}
然后可以通过三元表达式进一步简化
fun test(n: Int): Int = if (n <= 1) n else n * test(n - 1)
一行代码解决问题
尾递归函数是什么意思呢,它指的是函数末尾的返回值重复调用了自身函数。此时要在fun前面加上关键字tailrec,它告诉编译器这是一个尾递归函数,则编译器会相应进行优化,从而提高程序性能。
比如余弦不动点,即可通过尾递归函数来实现,下面是代码示例
tailrec fun findFixPoint(x: Double = 1.0): Double =
if (x == Math.cos(x)) x else findFixPoint(Math.cos(x))
=====================================================================
使用Java开发时,虽然系统自带的类已经提供了许多方法,然而经常还是无法完全满足业务需求,此时开发者往往要写一个工具类来补充相关的处理功能,长此以往,工具类越来越多,也越来越管理,针对于这个情况,Kotlin推出了扩展函数得概念,扩展函数允许开发者给系统类补写新的方法,而无须另外编写额外的工具类,比如系统自带的数组Array提供了求最大值的max方法,也提供了进行排序的sort方法,可以并未提供交换数组元素的方法,我们可以试着给Array数组来添加新的交换方法,也就是一个扩展函数。
如下所示:
fun Array.swap(pos1:Int,pos2:Int){
val tmp = this[pos1] //this表示数组自身
this[pos1] = this[pos2]
this[pos2] = tmp
}
不过这函数的缺点也很明显,就是它声明了扩展自Array< Int >,就不能用于浮点数组和双精度数组及其他的数组,所以,为了增强交换函数的通用性,必须把swap改写为泛型函数,即用T代替Int,改动代码如下:
fun Array.swap(pos1:Int,pos2:Int){
val tmp = this[pos1] //this表示数组自身
this[pos1] = this[pos2]
this[pos2] = tmp
}
扩展函数已经写好了,接下来使用一下吧
val array:Array = arrayOf(1.0,2.0,3.0,4.0)
btn_test.setOnClickListener {
//下标为0和3的两个数组元素进行交换
//array可以是整型数组,也可以是双精度数组
array.swap(0,3)
var str:String = “”
for (item in array){
str = str + item.toString() + “,”
}
tv_result.text = “数组元素排列结果为:$str”
}
尾声
如果你想成为一个优秀的 Android 开发人员,请集中精力,对基础和重要的事情做深度研究。
对于很多初中级Android工程师而言,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。 整理的这些架构技术希望对Android开发的朋友们有所参考以及少走弯路,本文的重点是你有没有收获与成长,其余的都不重要,希望读者们能谨记这一点。
这里,笔者分享一份从架构哲学的层面来剖析的视频及资料给大家梳理了多年的架构经验,筹备近6个月最新录制的,相信这份视频能给你带来不一样的启发、收获。
Android进阶学习资料库
一共十个专题,包括了Android进阶所有学习资料,Android进阶视频,Flutter,java基础,kotlin,NDK模块,计算机网络,数据结构与算法,微信小程序,面试题解析,framework源码!
大厂面试真题
PS:之前因为秋招收集的二十套一二线互联网公司Android面试真题 (含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)
《2019-2021字节跳动Android面试历年真题解析》
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!
for (item in array){
str = str + item.toString() + “,”
}
tv_result.text = “数组元素排列结果为:$str”
}
尾声
如果你想成为一个优秀的 Android 开发人员,请集中精力,对基础和重要的事情做深度研究。
对于很多初中级Android工程师而言,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。 整理的这些架构技术希望对Android开发的朋友们有所参考以及少走弯路,本文的重点是你有没有收获与成长,其余的都不重要,希望读者们能谨记这一点。
这里,笔者分享一份从架构哲学的层面来剖析的视频及资料给大家梳理了多年的架构经验,筹备近6个月最新录制的,相信这份视频能给你带来不一样的启发、收获。
[外链图片转存中…(img-1UA6V1iO-1715577239948)]
Android进阶学习资料库
一共十个专题,包括了Android进阶所有学习资料,Android进阶视频,Flutter,java基础,kotlin,NDK模块,计算机网络,数据结构与算法,微信小程序,面试题解析,framework源码!
[外链图片转存中…(img-1Vip1IkF-1715577239951)]
大厂面试真题
PS:之前因为秋招收集的二十套一二线互联网公司Android面试真题 (含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)
[外链图片转存中…(img-Y1hVe20E-1715577239953)]
《2019-2021字节跳动Android面试历年真题解析》
[外链图片转存中…(img-2MV2sdo4-1715577239954)]
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!