看来我是很难改掉我话唠这个毛病了,不信你往下看。
先聊点别的?
不聊点别的,心里憋得慌啊,不知道怎么开头啊,我这人就是聊着聊着话就多起来,所以老哥们莫慌,坐下来喝杯茶听我慢慢掰扯;
主持人:“你今年多大了?”
我:“这是人家的秘密(TMD哪里跑个主持人出来?)。”
主持人:“哟哟哟,不好意思都来了,懂~那你嫁了么?哦不对,娶了么?”
我:“这是大型征婚节目现场?不是聊聊Kotlin
的入门经验?”
主持人尴尬一笑,一副xxx(“欠揍”)的样子说到:“抱歉抱歉,职业习惯,职业习惯”,接着一本正经的说到“那你先简单的自我介绍一下您自己使用Kotlin
的情况吧,另外,在场的大佬可以先离开了,毕竟这是入门级别的东西,不耐看。”
正经的说点啥
其实在17年之前就已经注意到了Kotlin
,而且那时已经有一小撮人非常青睐Kotlin
,并在某些社区中疯狂输出。当时是被Kotlin深深吸引的,因为在工作之初我是做跨平台开发的(用C#
开发Android
和iOS
,当时还叫mono
,现在叫Xamarin
),所以当了解到Kotlin
能够应用在Android
、iOS
、Web
甚至Server
领域时,心里为之一抖:“这B装的可以啊”,出于当时的好奇心以及被Java
长久以来的诟病(繁琐、回调炼狱等)所折磨(大学学的Java,毕业工作用的C#,深感C#语言层面的优势),开始尝试Kotlin。
随着Kotlin的了解,深深的喜欢上了这门语言,当时Kotlin打着的旗号是与Java 100%互操作的,我胆子也比较大,便开始在一些场景使用Kotlin进行实际的应用场景开发,没记错的话当时的版本还是1.0x,紧接着5月份,Google宣布推荐Kotlin作为Android推荐开发语言,并且kt1.1版本随之发布。有了Google的大力支持,内心从此踏实,完全的拥入Kotlin的怀抱,至此便主要用Kotlin进行后续新业务开发和重构。
开发者们讨论语言时往往非常热闹,要是在群里说上一句“PHP是最好的语言”,哦不对,“Kotlin是Android开发的最好语言”,那就相当热闹了。也因此到现在,Kotlin可能还被一些人所质疑着。其实我也明白,大家心里有焦虑,有太多焦虑了,甚至焦虑隔壁的“Flutter大哥”跟“Aandroid老大哥”之间何去何从;不过焦虑始终是焦虑,我们干嘛要去焦虑今天大选的结果到底是“川建国”还是“懂王”呢,难道我的bug会因此少一点,所以与其焦虑不如先让自己Happy,不要每天自己都焦头烂额的,连自己的工作都应付不好的情况下,谈“焦虑”,会越来越“焦”,最后糊掉,被人收割;当然还要考虑实际的环境,有些想用但是又被条件制约,比如公司不采用,比如引进有困难,担忧对现有项目产生影响等种种问题;所以用还是不用,我们应该融入这个大圈子,站在自己所处的环境去考虑,我的建议就是如果你从事Android开发,并且也不会在短时间内改变这个现状也可以在项目中选择Kotlin,那就就不要拒绝使用Kotlin;
于我而言,使用Kotlin开发是幸福的,提高了我的工作效率,节省了开发时间,对于一名开发者来讲,这无疑是让人幸福的。
此时也许有人会犯嘀咕:“Kotlin不过是语法糖而已,哥不屑”,“Kotlin超多坑”,“Kotlin增大了编译时间”,“Kotlin太几把难学了”,“Kotlin的协程是什么鬼,有RxJava香么?”,“语言只是招式,内功才是王道”。。。。
这。。。你让我从何说起?是骡子是马,不要光听别人说,实践出真理,实操出贞操,一件事情值不值得去做,不能光凭别人怎么说。
来吧,Come on Kotlin,我们一起看看Kotlin到底是何方神圣。
说到这,我打开了Kotlin官方中文网站的学习文档,你们细品。
官方提供了非常好的学习资源,是我觉得学习Kotlin最好、最全的方式。官方文档地址奉上,小伙子,好好加油:看官方文档,靠谱儿;官方文档地址。
毕竟Kotlin是一门完完整整的语言,要是三言两语就能说清楚搞明白,那铁定扯淡,我也只是蜻蜓点水。
Hello,World
类、变量、方法是一个程序组成的最为普遍的三个要素,所以我们先搞清楚这三个东西就基本能入门了,其他的后面再提升。
为了避免太过于复杂,我们先来看一段中规中矩的代码,尽量的与Java
做对比;
///Study1.kt
//Study1.kt
class Study1 {//定义一个类
//定义一个String类型的只读变量
val content: String = "Hello,World."
//定义一个私有String类型的变量
private var name: String = "SuperLuo"
//定义一个protect类型的变量
protected var age:Int = 18
//构造函数
constructor(name: String):this(name,18)
constructor(name:String,age:Int){
this.name = name
this.age = age
}
//定义一个方法
fun sayHello() {
println(this.name + "说道:\"" + content + "\"");
}
//定义一个带参数的方法,计算两者之和
fun sum(a: Int, b: Int): Int {
return a + b
}
//定义一个私有的方法打印当前时间
private fun printCurrentDate(){
println(Date().toString())
}
}
麻雀虽小,五脏俱全,例子很简单,也是特意尽可能的用Java的形式来写的,毕竟大家对Java
比较熟。
由于Kotlin跟Java几乎是100%互操作的,也就是两者可以相互调用,这道理也很简单,毕竟两者都是jvm语言,那最终两者都会编译成为jvm支持的class文件。我门先搞懂上面的东西,再说其他,欠的债,一步一步还。
变量
kotlin通过val
和var
申明变量,两者之间的区别是val
赋值之后不能更改,而var
变量可以。
Kotlin具备一个很好的特性->“类型推断”;也就是如果可以通过变量值推断出变量是什么类型,则定义变量的时候,类型可以省略:
var x = 5 // 自动推断出 `Int` 类型
x += 1
当然存在Kotlin无法正确推断类型的情况,此时需要定义时指明类型,val content: String = "Hello,World."
;
在这里不得不提的是:Kotlin中,万物皆对象;
Java
中的基础类型都有与之对应的对象类型,比如int
的对象类型为Integer
,long
的对象类型为Long
;所以在Kotlin
中不存在基础类型,只有对象类型(其中整形类型为Int
而非Java中的Integer
,其他一样),至于为什么这么设计官方上面有说明,但是我看的不太懂,最开始我也觉得有点别扭,但是到后来我觉得这样也没什么坏毛病,反而规则的统一对一些事情反而有利,尤其是借助扩展函数;
举个实际例子,比如程序中很多地方都需要处理点赞量的显示,当点赞数为0时显示成“点赞”,大于1万时显示成“x.xxw”,那么我们可以像如下方式实现:
//定义一个扩展方法处理展示规则
inline val Int.asFavorString{
return when(this){
0->"点赞"
>10000 -> "${this.div(10000.0)}w"
else -> this
}
}
fun apply(){
val textView:TextView ....
//使用的时候,直接像1.asFavorString方法就可以调用了
textView.text = 1.asFavorString
}
当然上面的例子不是很恰当,而且更多的是体现了扩展函数的作用,不过先简单意会一下吧。
函数
Kotlin
使用fun
关键字申明函数,类似如下规则 :
(可见修饰符,比如private,默认为public) fun 函数名(参数列表):返回值{}
//带有两个参数的public方法
fun sum(a: Int, b: Int): Int {
return a + b
}
//无参数的私有方法
//该函数的返回值为Unit,Unit是Kotlin中一个比较特殊的对象(并且还是用单例方式实现的),类似Java中void的概念,可以理解为无返回值类型,因此返回值为Unit的函数,返回值类型可以不写
private fun printCurrentDate():Unit{
println(Date().toString())
}
//省略Unit的写法:等同于上一个函数
private fun printCurrentDate(){
println(Date().toString())
}
类
Kotlin
类的定义也是使用class
关键字,构造函数使用constructor
申明。总体来讲跟Java
差别不大。
使用
由于Kotlin
跟Java
是可以共存的,也就是两者混合开发,那就存在互相调用的情况,两者互相调用时有些情况会有细微差别;
Java
使用场景:
@Test
public void useStudyClassInJava() {
//创建对象
Study1 instance = new Study1("SuperLuo");
//打印content变量值
System.out.println("content=" + instance.getContent());
//调用对象函数
instance.sayHello();
//调用对象带参数的函数
int result = instance.sum(1, 2);
System.out.println("1+2=" + result);
}
Kotlin
使用场景:
@Test
fun useStudyClassInKt(){
//创建对象
val instance = Study1("SuperLuo")
//打印content变量值
println("content=${instance.content}")
//调用对象函数
instance.sayHello()
//调用对象带参数的函数
val result = instance.sum(1,2)
println("1+2=$result")
}
以上代码运行结果(两者结果相同):
content=Hello,World.
SuperLuo说道:"Hello,World."
1+2=3
从上面可以看到,两者不管从定义和使用上,只有细微的语法差别,所以上面的内容应该没有什么障碍;
不过眼尖的朋友可能还是看到了几个怪异的地方:
1、Kotlin创建对象时没有使用`new`关键字
2、Java代码访问对象的content变量时是使用的`getContent()`方法
至于第二个问题为什么会这样子,后面我会专门聊一下。
另外Kotlin的println函数其实就是调用的Java的System.out.println方法。
字符串拼接的时候,Kotlin我用了字符串模版的写法,其实比较等同于Java的String.format方法的效果
抽象类、接口
前面已经简单的了解了一下类、函数、变量,也进行了使用,类可以说是对程序来讲非常重要组成的元素,而跟类息息相关的另外东西是抽象类和接口;
抽象类
//与Java一样,使用abstrat定义抽象类
abstract class Person {
var name: String
val age: Int
//抽象属性:可以定义抽象属性和抽象方法,而Java只有抽象方法;其实Kotlin的抽象属性最终也会转换成抽象方法,后面专门聊
abstract val sex: String
constructor(name: String) {
this.name = name
//age 是val变量,赋值之后就不能再修改了
this.age = 18
}
//抽象方法
abstract fun getAddress(): String
fun printInfo() {
println("${name}今年${age}岁,性别${sex},住在${getAddress()}")
}
}
//抽象类的子类,使用:进行继承
class Male(name: String) : Person(name){
override val sex: String
get() = "男"
override fun getAddress(): String {
return "火星"
}
}
就不详细介绍了,可以先简单的看下注释。我们定义了一个抽象类,并且也定了一个子类,那么我们写个场景来使用这两个类;
@Test
fun testAbstract() {
val me = Male("小罗")
me.printInfo()
}
//执行结果:
小罗今年18岁,性别男,住在火星
与Java之间也没有特别大的差别,但是我们知道在Java开发中,我们可以创建匿名类来快速使用抽象类或者接口,这个大家应该就用的比较多了:
//创建了一个View.OnClickListener的匿名类对象
view.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
}
});
那在Kotlin中如何创建匿名类对象呢?上述代码在Kotlin中写法为:
view.setOnClickListener (object:View.OnClickListener{
override fun onClick(v: View?) {
}
})
//其实在Kotlin中上述写法还可以精简的写为,后面再具体说
view.setOnClickListener{
}
我们用匿名类的方式使用前面定义的Person类:
@Test
fun testAnonyClass(){
val she = object:Person("Siri"){
override val sex: String
get() = "女"
override fun getAddress(): String {
return "太阳"
}
}
she.printInfo()
}
//执行结果:
Siri今年18岁,性别女,住在太阳
接口
在Java
中,我们可以把接口当成一种特殊的抽象类,也就是接口所有的方法都是抽象的,但是在Kotlin
中却不同,Kotlin
中的接口既可以包含抽象方法的声明也可以包含实现。但是与抽象类不同的是,接口无法保存状态。
//定义枪的接口
interface Gun {
//攻击力:不同的枪攻击力不同
val power:Int
//打印攻击力
fun printPower(){
println("攻击力$power")
}
//定义一个抽象的射击方法
fun shoot()
}
class AK : Gun {
override val power: Int = 800
override fun shoot() {
println("使用AK射击")
}
}
//使用场景
@Test
fun testInterface() {
val ak = AK()
ak.printPower()
ak.shoot()
//匿名接口类实现
val waterGun = object : Gun {
override val power: Int
get() = 0
//重写了接口的默认实现逻辑
override fun printPower() {
println("水枪没有攻击力")
}
override fun shoot() {
println("使用水枪攻击")
}
}
waterGun.printPower()
waterGun.shoot()
}
//运行结果:
攻击力800
使用AK射击
水枪没有攻击力
使用水枪攻击
接口跟抽象类的使用很相似;
告一段落
说实话写基础很没劲。。哈哈,所以先草草的结束,暂时到这里吧,算做个了解,对于一门编程语言的把握还是建议进行系统的学习,所以还是希望看官方文档进行学习最好。
前面聊了这么点东西,可能有朋友心里开发犯嘀咕了,难道Kotlin
就这点东西?没意思!
我想说不是的,如果Kotlin
仅此而已的话,完全没有存在的必要,否则它仅仅是Java
的一个外国语版本罢了,反而恰恰相反;上面的代码场景很简单,其次我也有意将Kotlin
的代码写的尽可能好理解,尽可能的跟用Java
实现的方式一样,所以我们更难感受到Kotlin
的魅力,说白了,Kotlin
的“骚操作”还没有开始呢,因为怕整出太多与Java
方式不同的东西,会让萌新们一时间难以消化。我们慢慢来,慢慢的体会Kotlin
的骚操作吧。
后面我们主要围绕Kotlin
的实际应用以及一些“骚”操作来讲吧,感受一下Kotlin
的魅力,我也会更多的借助实际的使用场景来讲解。
欢迎入群交流:QQ276097690
更欢迎关注公众号
如果您有更多的建议或者交流,欢迎入群讨论,添加公众号更能第一时间了解最新内容。