Kotlin与java的纠缠史
1. 背景
Jetbrains早在2010年推出Kotlin,在今年(2017)5月18,谷歌在今日举行的I/O开发者大会上宣布,将Kotlin语言作为安卓开发的一级编程语言,这个可爱的语言可于Java进行无缝混编。之前做过一段时间的C#和python开发,感觉三者之间总两两相似,不清楚是谁在模仿谁,谁在吃着谁的语法糖。
2. 差异与对比
2.1 构造器
java | Kotlin |
---|---|
构造器 | 主构造器 |
- | 次构造器 |
- java版:
public class Model {public Model(){}public Model(String name){}
}
复制代码
- Kotlin版:
- 主构造器
class KtModel constructor(name: String)ps:如果不私有化构造器或者注解构造器,constructor可以省略,即:-> class KtModel (name: String)
复制代码
由于Kotlin主构造器写法的出现,可以简化Java中JavaBean,关键字:data
data class KtModel(var id: Int, var name: String)
复制代码
- Kotlin版
- 次构造器
class Model{var mName:String? = nullconstructor(name:String){mName = name}
}//由于Kotlin中有参数缺省写法,比如:
class Model{var mName:String? = nullconstructor(name:String,age:Int = 0){mName = name}
}//在java中实例化这个Model还是需要:
Model model = new Model("Inke",20)//为了让java也享受到这个福利,Kotlin支持@JvmOverloads注解,为Java重载构造器
class Model{var mName:String? = null@JvmOverloadsconstructor(name:String,age:Int = 0){mName = name}
}//此时:java调用
Model model = new Model("Inke",20);
Model model = new Model("Inke");
复制代码
2.2 自定义setter和getter
由data声明的javabean默认实现了getter方法,如果变量为var类型也同时实现了getter方法,并且像equal() hashcode() toString()方法也自动复写了。除此,也支持自定义setter和getter方法,写法和c#的方式一样。
class Student(var name: String, var grade: Int) {// Kotlin中的enumenum class LEVEL {GOOD, JUSTSOSO }//默认规则赋值var level: LEVEL = if (grade > 90) LEVEL.GOOD else LEVEL.JUSTSOSOset(value) {field = value}get() = field
}
ps: 通过field代表set get的属性复制代码
2.3 条件筛选
java中对某一字段类型根据不同的值进行筛选,同使用Switch“语句”,如:
switch (itemViewType) {case ITEM_VIEWTYPE_LINKMSG:// 带有link字段的链接消息return new LinkMsgViewHolder(inflater);case ITEM_VIEWTYPE_TEXTMSG_BYME:// 自己的文本消息return new TextMsgByMeViewHolder(inflater);case ITEM_VIEWTYPE_TEXTMSG_BYOTHER:// 别人的文本消息return new TextMsgByOtherViewHolder(inflater);case ITEM_VIEWTYPE_PIC_MSG_ME:// 自己的图片消息return new PicMsgByMeViewHolder(inflater);case ITEM_VIEWTYPE_PIC_MSG_OTHER:// 别人的图片消息return new PicMsgByOtherViewHolder(inflater);case ITEM_VIEWTYPE_AUDIO_MSG_ME:// 自己的语音消息...}
复制代码
kotlin中对某一字段类型筛选的关键字when,但它不属于语句,它属于表达式,真的是表达式哦。
fun getWeekInfo(day: Int): String {//因为是函数 所以可以直接使用在return后面return when (day) {1, 2, 3, 4, 5 -> "工作日"6, 7 -> "周末"else -> "unknow"}
}在Kotlin中几乎一切都是表达式,所以上面更有简化版:fun getWeekInfo(day: Int) = when (day) {1, 2, 3, 4, 5 -> "工作日"6, 7 -> "周末"else -> "unknow" //与java的default不能,else必须写,除非密封类(sealed class)可以不写,后面会详细讲解。
}
复制代码
难道仅仅这些就够了,错,还有厉害的!前方高能。
fun getWeekInfo(student: Student) = when {student.name.equals("马云") -> "考什么试!"student.grade >= 60 -> "Pass"student.grade < 60 -> "fail"student is Student -> "is 相当于 instanceof"else -> "unknow"
}1. when可以不一定带参数,就使用方法参数
2. when中的条件不需要同一种方式判断,只需要返回boolean类型
复制代码
2.4 循环结构
语言 | 次数迭代 | 对象池迭代 |
---|---|---|
java | 支持 | 支持 |
kotlin | 强支持 | 支持 |
java版本两种循环方式的写法
for (int i = 0; i < 10; i++) {//TODO}for (String arg : args) {//TODO}
复制代码
kotlin版本,与python写法相似
// 次数迭代
for(i in 1..10){ //[1,10]区间往上遍历print(i)}for(i in 10 downTo 1){ // [1,10]区间往下遍历print(i)}for(i in 1 until 10){ // [1,10)区间往上遍历print(i)}for(i in 1..10 step 2){ //设置步数往上走print(i)}//对象池迭代
for (arg in args){print(arg)}
复制代码
2.5 引入静态方法
引入静态方法的目的:
java | Kotlin |
---|---|
工具方法 | 类的扩展 |
引入方式:
- java: import static com.meelive.ingkee.base.utils.guava.Preconditions.checkArgument;
- Kotlin: import com.inke.utils.showToast
静态方法的写法
- java:纯工具类的写法
- kotlin:
fun Context.showToast(message: String) : Toast {var toast : Toast = Toast.makeText(this,message,Toast.LENGTH_SHORT)toast.setGravity(Gravity.CENTER,0,0)toast.show()return toast
}作为Context类的拓展方法,在Activity,Service中,可以直接使用,面向对象的封装性显得更加的严实(个人看法)。
复制代码
2.6 类型转换
java中对于类型的转化,写的特别想吐的语句如下:
Person p = new Person();
if(p instanceof Student){Student student = (Student) p;String id = student.uid;
}
复制代码
然后看看Kotlin的模仿版:
val p = Person()
if (p is Student) {val student = p as Studentvar uid = student.uid
}
复制代码
瞪大眼睛看看简化版,找不同的时间到了!
val p = Person()
if (p is Student) {var uid = p.uid
}is 进行判断后,Person类实例就已经装成Student类实例了,这就是Kotlin的智能类型转化。
复制代码
2.7 单例
- java版单例(懒汉式和饿汉式),懒汉式如下:
public static RoomManager ins() {return SingletonHolder.INSTANCE;
}private static class SingletonHolder {private static final RoomManager INSTANCE = new RoomManager();
}
复制代码
- kotlin版
class AppManager private constructor(var info: String) {companion object {private var INSTANCE: AppManager? = nullfun getInstance(info: String): AppManager {if (INSTANCE == null) {synchronized(AppManager::class.java) {if (INSTANCE == null) {INSTANCE = AppManager(info)}}}return INSTANCE!!}}fun getPhoneInfo(arg: String): String? {return null}
}
复制代码
如果是无参单例,有更为简单的写法
/*** Created by YangLang on 2017/7/29.*/
object AppManager {fun getPhoneInfo(arg: String): String? {return null}
}
复制代码
2.8 正则表达式
- java的写法
String info = "12,34,56.789";
String[] split = info.split("[,.]");
for (String s : split) {System.out.println(s);
}java默认使用正则去切割
复制代码
- Kotlin写法
var info = "12,34,56.789"for (s in info.split(",",".")) {println(s)}kotlin 为了编程更加口头化,生活化,默认不使用正则,上面写法的理解是,把info用","或者"."进行分割。//进一步说明
info.split(".")
1. 在java中输出为空,因为.在正则规则中为统配符
2. 在kotlin中输出为12,34,56和789,因为Kotlin默认不使用正则,所以.只是一个普通的字符。
复制代码
2.9 嵌套类和内部类
说明: 嵌套类不含有外部类的引用,内部类拥有外部类的引用,正因为这样,也可以造成Activity没有释放,而内存泄漏问题。
- java
public class Outter {//包含Outter类的引用,可以使用Outter的方法class Intter{}// 不包含Outter类引用,不能使用Outter的方法static class NotIntter{}
}
复制代码
- Kotlin
class Outter {inner class Intterclass NotIntter
}
复制代码
java默认为内部类,Kotlin默认为嵌套类,一定程度的避免造成内存泄漏无意识写法。
2.10 密封类
密封类的概念和C#一样,密封类可以被继承,但本身不能被实例化。所有的子类必须在同一文件中,相当于把密封类的子类都封装在一块,可以配合when使用。
sealed class BaseModel{}
class FirstModel:BaseModel(){}
class SecondModel:BaseModel(){}
复制代码
fun justDo(baseModel: BaseModel) = when(baseModel){is FirstModel -> ""is SecondModel -> ""
}没有使用else,但是必须要写全baseModel的子类,如果编写期间新创建一个类继承BaseModel,此处when直接报错,密封类的这种特性,保证编写when表达式时,可以无一疏漏的考虑到每一种情况,约束代码的编写。
复制代码
2.11 代理
代理方式\语言 | java | Kotlin |
---|---|---|
静态代理 | √ | √ |
动态代理 | √ | √ |
属性代理 | × | √ |
标准代理 | × | √ |
这里不讲java的设计模式,主要关注Kotlin的代理模式,从类代理、属性代理、标准代理三个方面
- 类代理
假如我们需要创建AnimatorListener的实例,Java中最常见的方式可能是匿名内部类,我们需要重载它的四个方法,虽然我们不都用,这样代码就显得多余。Kotlin中就可以用该接口得一个实现类代为重载,并处理自己的TODO。
class MyAnimatorListener(var animatorListener: Animator.AnimatorListener):Animator.AnimatorListener by animatorListener{override fun onAnimationEnd(animation: Animator?) {//TODO 可以进行预处理animatorListener.onAnimationEnd(animation)}
}接口Animator.AnimatorListener需要的方法由传入参数animatorListener实现了,该MyAnimatorListener也通过关键字by,将需要实现的方法让animatorListener代为实现,重载方法后可以做预处理操作。
复制代码
- 属性代理
当使用val修饰属性时,表明属性为不可修改,代理类继承ReadOnlyProperty<被代理类,类型>类
当使用var修饰时,属性可修改,代理类继承ReadWriteProperty<Water,Boolean>
/*** Created by YangLang on 2017/7/29.*/
fun main(args: Array<String>) {var p = Person("inke", 21)println("是否已经成人: ${p.isAdult}")
}class Person(var name: String, var age: Int) {var isAdult: Boolean by isAdultProperty()
}class isAdultProperty : ReadWriteProperty<Person, Boolean> {override fun setValue(thisRef: Person, property: KProperty<*>, value: Boolean) {}override fun getValue(thisRef: Person, property: KProperty<*>): Boolean {return thisRef.age > 18}
}
复制代码
- 标准代理
Kotlin标准代理有lazy(),observable(),notNull().. 所有这样Kotlin自建代理都在delegates类下,主要讲lazy(懒加载) 在java中使用supplier和suppliers进行懒加载(延时求值),在kotlin中通过方法lazy直接延时求值,更快更强!!
class InfoConfig {val info: String by lazy {"Inke info"}
}fun main(args: Array<String>) {print(InfoConfig().info)
}第一次获取info值时,会通过lazy函数传入的函数参数进行求值,以后再获取该值时,直接返回,所以懒加载可进行复杂计算。
复制代码
2.12 属性赋初值问题
属性不管申明为val还是var都必须赋初值,我们只能被迫写成 var info:String? = null。但是实际情况下有些属性不允许赋予无意义的初值如null,我总结有三种方式处理(可能不全面):
- lateinit var info: String(只能用在var类型上)
- class Student(var name: String, var age: Int){ val isAudit = age > 18} (可用在var或者val上,但只是在初始化时赋一次值~)
- val info: String by lazy { "Inke info" } (只能用在val类型上)
2.13 lambda的概要(对象引用,数组用法)
用lambda表达式创建函数“变形体”
var add = { x: Int, y: Int -> x + y }print(add(1,2))
复制代码
lambda缩写演史
// 1. 匿名内部类
rb_home.setOnClickListener(object:View.OnClickListener{override fun onClick(v: View?) {}
})// 2. 如果内部类中只有一个方法,缩写成lambda表达式rb_home.setOnClickListener({v -> Unit})// 3. 如果函数参数最后一个参数为lambda表达式,可以提取放在函数参数括号外面rb_home.setOnClickListener(){v -> Unit}// 4. 如果函数参数括号为空,可以省略rb_home.setOnClickListener{v -> Unit}// 5. 如果lambda表达式形参咩有使用,可以省略rb_home.setOnClickListener{Unit} <==> rb_home.setOnClickListener{//TODO}复制代码
可以根据以上的省略原则可以定义我们自己的的函数。如在java中做版本的判断,我们会写:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {webSettings.setAllowUniversalAccessFromFileURLs(true);
}这样写起来不流程,而且不易复用
复制代码
Kotlin上面可以这样定义函数
inline fun UP_VERSIONJELLY_BEAN(function: () -> Unit){if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEA){function()}
}在使用时,可以毫不犹豫的写成这样:
UP_VERSIONJELLY_BEAN{//TODO
}复制代码
2.14 反射中优质提升
public class Test<T> {public Test() {}
}复制代码
以上的泛型写法,在java中运行时由于类型擦除的原因,无法确定T的类型,很难获取该对象的字节码对象,不过在早两天看到Guava支持运行时获取泛型类型,通过TypeToken工具类。但是在Kotlin可以轻松解决这样问题,通过标注关键字reified。
- TypeToken
- reified关键字使用
inline fun <reified T: Activity> Activity.newIntent() {val intent = Intent(this, T::class.java)startActivity(intent)
}
复制代码
2.15 let apply run with的区别
传送门地址
Kotlin与java的纠缠史相关推荐
- 开发Android应用用Kotlin还是Java?
还记得多年前有关Android与iOS孰优孰劣的辩论吗?如今,Kotlin与Java的争论,时常广泛地发生在开发人员之中.不过,由于大家往往关注的是Java所不具备的Kotlin功能,因此他们的结论可 ...
- java集合框架史上最详解(list set 以及map)
title: Java集合框架史上最详解(list set 以及map) tags: 集合框架 list set map 文章目录 一.集合框架总体架构 1.1 集合框架在被设计时需满足的目标 1.2 ...
- 《From Java To Kotlin》-Kotlin与Java的简单对比
前言: 原文来自https://github.com/MindorksOpenSource/from-java-to-kotlin 本文也只是简单比较kotlin与java的不同之处,实际学习kotl ...
- 【Kotlin】apply 内联扩展函数 ( apply 函数原型 | apply 函数示例 | Kotlin 调用 Java API )
文章目录 I . 内联扩展函数 apply II . Kotlin 调用 Java API III . apply 内联扩展函数示例 ( 调用 Java API 处理图像 ) I . 内联扩展函数 a ...
- kotlin与java对比
为什么80%的码农都做不了架构师?>>> kotlin作为一个现代的适用于多平台的静态类型语言越来越受到java开发同学的喜爱,尤其是android开发同学的喜爱,下面从几个方 ...
- Kotlin极简教程:第10章 Kotlin与Java互操作
Kotlin is 100% interoperable with Java™ and Android™ 在前面的章节中,我们已经学习了Kotlin的基础语法.类型系统.泛型与集合类.面向对象与函数式 ...
- Kotlin 与 Java有什么区别(最全最新的)
目录 什么是Kotlin? 什么是Java? 主要区别: Kotlin 的特点 Java的特点 Kotlin 的历史 JAVA的历史 Kotlin 和 Java 的区别 Kotlin 的优势 Java ...
- Kotlin与Java之争
Kotlin \\ Kotlin是一门相对比较新的JVM语言,JetBrains自2011年以来一直在积极地开发. \\ 多年来,该语言在Android社区受到的关注度越来越高,并在Google IO ...
- 入门 Kotlin 和 Java 混合开发
一.前沿 如果你学习过其他的编程语言,你就会发现 Java 的语法很是哆嗦,可是我们为什么没有放弃 Java 这门编程语言呢?因为 JVM 是一个非常好的平台,而且 Java 程序员目前在中国所占的比 ...
最新文章
- Vue.js 生命周期
- 用 Python 实现答题卡识别!
- A站、B站、C站、D站、E站、F站、G站、H站、I站、J站、J站、L站、M站、N站…Z站?...
- mysql 删除 修改数据库语句_数据库——添加,修改,删除
- ToolPart的简单开发
- 安装cv2(opencv-python)遇到的问题
- 第三章 最小化SpringXml 配置
- android canvas 网络图,【巨坑:toDataURL】canvas合成网络图片
- 如何初始化一个vue项目
- Clos Network
- 异常总结2013-04
- MacOS怎么设置动态桌面,heic动态桌面壁纸怎么用
- 《Unix编程艺术》chm 电子书下载
- SQL Server 使用SQL获取建表语句
- 福昕PDF阅读器 Foxit PDF Reader 中文绿色版
- 搭建资金运营体系提高企业的运营能力
- CSS 特殊性(Specificity)
- 模具毕业设计题目推荐 / 毕业设计(论文)说明书 CAD图纸 三维模型 开题报告 任务书 实习报告 答辩 ……
- 17 个 JVM 参数
- 电脑卡顿,终于解决了多年的电脑卡顿问题
热门文章
- 不知道变年轻特效软件有哪些?这些有趣的app建议收藏
- CSDN上海城市开发者社区线下活动纪实
- ie加载项存在残留是什么_如何用百度杀毒清除IE浏览器加载项残余
- 2023微信红包封面怎么自己制作(入口+步骤)
- ⅰsee是什么意思_I see 什么意思
- QGraphic view实例:利用QGraphicsItem与定时器实现动画效果:蝴蝶飞舞
- c语言万年历制作落差,用C语言制作万年历
- 腾讯云游戏开发者技术沙龙,1月19日杭州站报名开启啦!
- 电子科技大学-《图论》-研究生课程-知识点汇总-anki卡片定义定理整理-503张卡片
- 微信自定义tabbar有小红点_微信小程序自定义 tabbar