### Kotlin与Java中的操作对比
#### 语法格式对比
在之前内容中,我们已经介绍了Java与Kotlin互操作的基本方式。为了更好地了解Java与Kotlin语言,本小节我们将通过使用Java与Kotlin来实现一些基本功能,以横向对比来直观地看出这两种语言的异同。
1. 打印语句
在Java和Kotlin中,换行与不换行打印的语句对比的具体代码如下所示:
(1)Java代码
```
System.out.print("java");
System.out.println("java");
```
(2)Kotlin代码
```
print("kotlin")
println("kotlin)
```
上述代码中,不换行打印语句使用的方法是print(),换行打印语句使用的方法是println()。
2. 常量与变量
在Java与Kotlin中,创建常量与变量的具体代码如下所示:
(1)Java代码
```
String name = "张三";
final String name = " 张三";
```
(2)Kotlin代码
```
var name = "张三"
val name = "张三"
```
上述代码中,在Java中创建一个变量直接用“变量类型类型名”即可,创建一个常量需要使用final关键字。在Kotlin中创建一个变量使用var关键字,创建一个常量使用val关键字。
3. null的声明
在Java和Kotlin中,null声明的具体代码如下所示:
(1)Java代码
```
String otherName;
otherName = null;
```
(2)Kotlin代码
```
var otherName:String?
otherName = null
```
上述代码中可以看出,给变量申明值为null时,在Java中直接将变量赋值为null即可,在Kotlin中首先需要通过“?”设置该变量的值可以为null,然后才可以将该变量设置为null。
4. 空判断
Java与Kotlin中对文本信息进行空判断的具体代码如下所示:
(1)Java代码
```
if(text != null){
int length = text.length();
}
```
(2)Kotlin代码
```
if(text != null){
int length = text.length();
}
```
上述代码中,在Java中通过“!=”来判断文本信息text是否为null,在Kotlin中通过“?.”的形式来判断文本信息text是否为null。
5. 换行
在Java中,进行字符串换行需要通过“\n”来实现,具体代码如下所示:
```
String text = "FirstLine\n" + "secondLine\n" + "ThirdLine";
```
在Kotlin中,进行字符串换行需要将字符串换行并且该字符串前方需加上“|”,具体代码如下所示:
```
val text = """
|FirstLine
|SecondLine
|ThirdLine""".trimMargin()
```
6. 三元表达式
在Java中,三元表达式是通过“(条件表达式)?表达式1:表达式2;(若为真输出1,若为假输出2)”来实现的。在Kotlin中,三元表达式是通过if…else条件语句来实现的,具体代码如下所示。
(1)Java代码
```
int max = a>b?a:b
```
(2)Kotlin代码
```
val max = if(a>b) a else b
```
7. 操作符
在Java和Kotlin中的操作符的对比,如表12-1所示。
![](https://img.kancloud.cn/35/c7/35c7936651cec10e6fbc7b1103c3defc_1366x310.png)
:-: 表12-1 操作符
在表12-1中,左边是Java对应的操作符,右边是Kotlin对应的操作符,这些操作符是一一对应关系。
8. 区间
在Java和Kotlin中区间的表示方法也是不同的,例如判断一个变量是否在一个区间中的具体代码如下所示:
(1)Java代码
```
if(score>=0&&score<=300){}
```
(2)Kotlin代码
```
if(score in 0..300){}
```
9. 多分支判断语句
在Java和Kotlin中多分支判断语句使用的关键字是不同的,Java中使用的是switch关键字,Kotlin中使用的是when关键字。具体代码如下所示:
(1)Java代码
```
int a = 1;
switch (a) {
case 1:
break;
case 2:
break;
}
```
(2)Kotlin代码
```
var a: Int = 1
when (a) {
1 -> println("你好")
2 -> println("Hello")
}
```
10. for循环
在Java和Kotlin的for循环语句中循环条件写法不同,具体代码如下所示:
(1)Java代码
```
for(int i=1;i<=10;i++){}
```
(2)Kotlin代码
```
for(o in 1..10){}
```
11. 快速创建集合操作
在Java和Kotlin中分别来创建一个List集合和Map集合。在Java中创建集合的具体代码如下所示:
```
List<String> list = Arrays.asList("张三", "李四", "王五");
Map<String, Integer> map = new HashMap<String, Integer>();
```
在Kotlin中创建集合的具体代码如下所示:
```
val list = listOf("张三"," 李四"," 王五")
val map = mapOf("Jack" to 10)
```
12. 构造器私有化
在Java中,构造器私有化的代码如下所示:
```
class NetManager{
private NetManager(){}
}
```
在Kotlin中,构造器私有化的代码如下所示:
```
class NetManager private constructor(){}
```
13. 静态代码块
在Java中静态代码块只需通过static关键字来修饰,但是在Kotlin中,放置在伴生对象中的代码块就称为静态代码块,具体代码如下所示:
(1)Java代码
```
static {
System.out.println("代码块");
}
```
(2)Kotlin代码
```
companion object {
init {
println("代码块")
}
}
```
#### 异常检查对比
在Kotlin中,所有异常都是非受检(Non-Checked Exception)的,编译器不会强制捕获其中的任何一个异常。而在Java中,编译器会强制要求处理会产生的异常。接下来我们通过一个案例来演示在Kotlin中调用Java中会产生异常的代码。
1. 创建ThrowException.java
创建一个名为ThrowException的Java类,在该类中创建一个divide()方法,具体代码如【文件12-21】所示。
【文件12-21】ThrowException.java
```
public class ThrowException {
public static int divide(int a, int b) throws Exception {
if (b == 0) {
throw new Exception();
} else {
return a / b;
}
}
public static void main(String[] args) throws Exception {
int result = divide(4, 0);
System.out.println(result);
}
}
```
运行结果:
```
Exception in thread"main"com.itheima.chapter12.Exception
at com.itheima.chapter12.ThrowException.divide(ThrowException.java:5) at com.itheima.chapter12.ThrowException.main(ThrowException.java:11)
```
从上述代码可以看出,当b=0时,a/b会抛出异常。在Java中,编译器会强制要求处理这个异常。
2. 创建ThrowException.kt
创建一个ThrowException.kt文件,在该文件中创建一个divide()方法,具体代码如【文件12-22】所示。
【文件12-22】ThrowException.kt
```
fun divide(a: Int, b: Int): Int {
var result: Int = a / b // 定义一个result 变量用于存放a/b 的值
return result // 将结果返回
}
fun main(args: Array<String>) {
var result = divide(5, 0) // 调用divide() 方法
println(result)
}
```
运行结果:
```
Exception in thread"main"java.lang.ArithmeticException:/by zero
at com.itheima.chapter12.ThrowExceptionKt.divide(ThrowException.kt:3)
at com.itheima.chapter12.ThrowExceptionKt.main(ThrowException.kt:7)
```
根据上述代码的运行结果可知,在Kotlin中,调用divide()方法时,虽然编译器不会强制要求处理这个异常,但是运行该程序时会报异常。
#### 可变参数对比
在程序中可以向一个函数传递多个参数,此时这个函数的参数可以用可变参数来表示。Kotlin和Java中都有可变参数,只是表示方式不太一样。在Java中用“…”表示可变参数,在Kotlin中用vararg关键字来表示可变参数,这些可变参数传递到函数中后都是一个数组。接下来我们通过两个案例来分别演示在Java中和Kotlin中的可变参数的使用。
1. Java中可变参数的使用
在Java中,将可变参数传递到函数中并求和,具体代码如【文件12-23】所示。
【文件12-23】Params.java
```
public class Params {
public static void main(String[] args) {
int result = sum(10, 20, 30);
System.out.println(result);
}
public static int sum(int... params) {
int result = 0;
for (int i = 0; i < params.length; i++) {
result += params[i];
}
return result;
}
}
```
运行结果:
```
60
```
2. Kotlin中可变参数的使用
在Kotlin中,将可变参数传递到函数中并求和,具体代码如【文件12-24】所示。
【文件12-24】Params.kt
```
fun main(args: Array<String>) {
println(sum(10, 20, 30))
}
fun sum(vararg params: Int): Int {
var result = 0
params.forEach {
result += it
}
return result
}
```
运行结果:
```
60
```
#### 类的class对象对比
在Java中,获取一个类的class对象有两种方式,这两种方式如下所示:
```
第1种方式:类.class
第2种方式:类的对象.getClass()
```
在Kotlin中,获取一个类的class对象也有两种方式,这两种方式如下所示:
```
第1 种方式:val clz1 = 类::class.java
第2 种方式:val clz2 = 类的对象.javaClass
```
Kotlin中的第1种方式对应Java中的第1种方式,Kotlin中的第2种方式对应Java中的第2种方式。
在Java中,.class在编译阶段已经确定了类型,getClass()则是在运行阶段才能确定它的类型。同样在Kotlin中,对应的::class.java与.javaClass的区别与Java中是一样的。接下来我们通过一个案例来观察.class与getClass()获取的类的class对象是否是一样的,具体代码如【文件12-25】所示。
【文件12-25】ObjectDemo.java
```
public class ObjectDemo {
public static void main(String[] args) {
Animal animal = new Dog();
System.out.println(Animal.class.getName()); //输出Animal
System.out.println(animal.getClass().getName()); //输出Dog
}
static class Animal {
}
static class Dog extends Animal {
}
}
```
运行结果:
```
com.itheima.chapter12.ObjectDemo$Animal
com.itheima.chapter12.ObjectDemo$Dog
```
根据上述代码的第5、6行与该程序的运行结果可知,.class在编译时已经确定了类型是Animal,而getClass()在编译时没有确定类型,在运行时才确定了它的类型为Dog。
在Kotlin中可以使用::class.java或者.javaClass进入Java的反射类java.lang.Class,之后可以使用Java中的反射功能特性。
#### 成员控制权限对比
在Kotlin和Java中的属性用不同的关键字来修饰会控制属性的权限,接下来我们将针对这几个关键字进行详细的讲解。
1. Java中的权限控制
在Java中有以下几个关键字来修饰创建的成员或类,并指定这些成员或类的控制权限。
* private(当前类访问级别):如果类的成员被private访问控制符来修饰,则这个成员只能被该类的其他成员访问,其他类无法直接访问。类的良好封装就是通过private关键字来实现的。
* default(包访问级别):如果一个类或者类的成员不使用任何访问控制符修饰,则称它为默认访问控制级别,这个类或者类的成员只能被本包中的其他类访问。
* protected(子类访问级别):如果一个类的成员被protected访问控制符修饰,那么这个成员既能被同一包下的其他类访问,也能被不同包下该类的子类访问。
* public(公共访问级别):这是一个最宽松的访问控制级别,如果一个类或者类的成员被public访问控制符修饰,那么这个类或者类的成员能被所有的类访问,不管访问类与被访问类是否在同一个包中。
接下来我们通过一个表将这四种访问级别更加直观地表示出来,如表12-2所示。
![](https://img.kancloud.cn/e6/2a/e62a5c063765561b09f50ed8373823dc_1368x274.png)
:-: 表12-2 访问控制级别
2. Kotlin中的权限控制
在Kotlin中也有4个关键字来修饰创建的成员和类,其中private、public、protected这3个关键字与Java中是一样的,不过Kotlin中多了一个Internal关键字。
* Internal(包访问级别):主要指的是一个包的权限,也就是在同一个包中可以使用。
#### 默认参数函数对比
在Kotlin中,创建一个带有默认参数值的函数时,程序会对每个有默认值的参数生成一个重载函数,在Kotlin中调用该函数时,可以传递有默认值的参数,也可以不用传递,但是在Java中调用时,必须传递所有参数。接下来我们通过一个案例来演示在Kotlin中和Java中调用有默认值参数的函数。
1. 创建NetManager.kt
创建一个NetManager.kt文件,在该文件中创建一个有默认值参数的函数sendRequest()。具体代码如【文件12-26】所示。
【文件12-26】NetManager.kt
```
class NetManager {
//有默认值参数的函数
fun sendRequest(path: String, method: String = "GET") {
println("发送请求,请求方式=$method 路径=$path")
}
}
fun main(args: Array<String>) {
val manager = NetManager()
//传递一个path参数
manager.sendRequest("http://www.baidu.com")
//传递一个path参数和一个method参数
manager.sendRequest("http://www.baidu.com", "POST")
}
```
运行结果:
```
发送请求,请求方式=GET路径=http://www.baidu.com
发送请求,请求方式=POST路径=http://www.baidu.com
```
上述代码中,创建了一个NetManager类,并在该类中创建了一个sendRequest()函数,这个函数中有两个参数,分别为path、method,并为method这个参数设置了一个默认值GET。由于在Kotlin中,程序对有默认值参数的函数都会生成一个重载函数,因此在调用sendRequest()函数时,可以只传递一个path参数或者同时传递path和method两个参数。从运行结果可以看出,在调用sendRequest()函数时,只传递一个path参数,此时程序默认的method参数的值就为GET。
2. 创建OverLoad.java
创建一个OverLoad.java文件,调用【文件12-26】中NetManager类中的sendRequest()方法。具体代码如【文件12-27】所示。
【文件12-27】OverLoad.java
```
public class OverLoad {
public static void main(String[] args) {
NetManager manager = new NetManager();
//必须传递sendRequest()方法中所有的参数
manager.sendRequest("http://www.baidu.com", "GET");
}
}
```
运行结果:
```
发送请求,请求方式=GET路径=http://www.baidu.com
```
根据上述代码可知,在Java中调用Kotlin中有默认参数的函数时,必须传递该函数中的所有参数。
- 前言
- Kotlin简介
- IntelliJ IDEA技巧总结
- idea设置类注释和方法注释模板
- 像Android Studion一样创建工程
- Gradle
- Gradle入门
- Gradle进阶
- 使用Gradle创建一个Kotlin工程
- 环境搭建
- Androidstudio平台搭建
- Eclipse的Kotlin环境配置
- 使用IntelliJ IDEA
- Kotlin学习路线
- Kotlin官方中文版文档教程
- 概述
- kotlin用于服务器端开发
- kotlin用于Android开发
- kotlin用于JavaScript开发
- kotlin用于原生开发
- Kotlin 用于数据科学
- 协程
- 多平台
- 新特性
- 1.1的新特性
- 1.2的新特性
- 1.3的新特性
- 开始
- 基本语法
- 习惯用法
- 编码规范
- 基础
- 基本类型
- 包与导入
- 控制流
- 返回与跳转
- 类与对象
- 类与继承
- 属性与字段
- 接口
- 可见性修饰符
- 扩展
- 数据类
- 密封类
- 泛型
- 嵌套类
- 枚举类
- 对象
- 类型别名
- 内嵌类
- 委托
- 委托属性
- 函数与Lambda表达式
- 函数
- Lambda表达式
- 内联函数
- 集合
- 集合概述
- 构造集合
- 迭代器
- 区间与数列
- 序列
- 操作概述
- 转换
- 过滤
- 加减操作符
- 分组
- 取集合的一部分
- 取单个元素
- 排序
- 聚合操作
- 集合写操作
- List相关操作
- Set相关操作
- Map相关操作
- 多平台程序设计
- 平台相关声明
- 以Gradle创建
- 更多语言结构
- 解构声明
- 类型检测与转换
- This表达式
- 相等性
- 操作符重载
- 空安全
- 异常
- 注解
- 反射
- 作用域函数
- 类型安全的构造器
- Opt-in Requirements
- 核心库
- 标准库
- kotlin.test
- 参考
- 关键字与操作符
- 语法
- 编码风格约定
- Java互操作
- Kotlin中调用Java
- Java中调用Kotlin
- JavaScript
- 动态类型
- kotlin中调用JavaScript
- JavaScript中调用kotlin
- JavaScript模块
- JavaScript反射
- JavaScript DCE
- 原生
- 并发
- 不可变性
- kotlin库
- 平台库
- 与C语言互操作
- 与Object-C及Swift互操作
- CocoaPods集成
- Gradle插件
- 调试
- FAQ
- 协程
- 协程指南
- 基础
- 取消与超时
- 组合挂起函数
- 协程上下文与调度器
- 异步流
- 通道
- 异常处理与监督
- 共享的可变状态与并发
- Select表达式(实验性)
- 工具
- 编写kotlin代码文档
- 使用Kapt
- 使用Gradle
- 使用Maven
- 使用Ant
- Kotlin与OSGI
- 编译器插件
- 编码规范
- 演进
- kotlin语言演进
- 不同组件的稳定性
- kotlin1.3的兼容性指南
- 常见问题
- FAQ
- 与Java比较
- 与Scala比较(官方已删除)
- Google开发者官网简介
- Kotlin and Android
- Get Started with Kotlin on Android
- Kotlin on Android FAQ
- Android KTX
- Resources to Learn Kotlin
- Kotlin样品
- Kotlin零基础到进阶
- 第一阶段兴趣入门
- kotlin简介和学习方法
- 数据类型和类型系统
- 入门
- 分类
- val和var
- 二进制基础
- 基础
- 基本语法
- 包
- 示例
- 编码规范
- 代码注释
- 异常
- 根类型“Any”
- Any? 可空类型
- 可空性的实现原理
- kotlin.Unit类型
- kotlin.Nothing类型
- 基本数据类型
- 数值类型
- 布尔类型
- 字符型
- 位运算符
- 变量和常量
- 语法和运算符
- 关键字
- 硬关键字
- 软关键字
- 修饰符关键字
- 特殊标识符
- 操作符和特殊符号
- 算术运算符
- 赋值运算符
- 比较运算符
- 逻辑运算符
- this关键字
- super关键字
- 操作符重载
- 一元操作符
- 二元操作符
- 字符串
- 字符串介绍和属性
- 字符串常见方法操作
- 字符串模板
- 数组
- 数组介绍创建及遍历
- 数组常见方法和属性
- 数组变化以及下标越界问题
- 原生数组类型
- 区间
- 正向区间
- 逆向区间
- 步长
- 类型检测与类型转换
- is、!is、as、as-运算符
- 空安全
- 可空类型变量
- 安全调用符
- 非空断言
- Elvis操作符
- 可空性深入
- 可空性和Java
- 函数
- 函数式编程概述
- OOP和FOP
- 函数式编程基本特性
- 组合与范畴
- 在Kotlin中使用函数式编程
- 函数入门
- 函数作用域
- 函数加强
- 命名参数
- 默认参数
- 可变参数
- 表达式函数体
- 顶层、嵌套、中缀函数
- 尾递归函数优化
- 函数重载
- 控制流
- if表达式
- when表达式
- for循环
- while循环
- 循环中的 Break 与 continue
- return返回
- 标签处返回
- 集合
- list集合
- list集合介绍和操作
- list常见方法和属性
- list集合变化和下标越界
- set集合
- set集合介绍和常见操作
- set集合常见方法和属性
- set集合变换和下标越界
- map集合
- map集合介绍和常见操作
- map集合常见方法和属性
- map集合变换
- 集合的函数式API
- map函数
- filter函数
- “ all ”“ any ”“ count ”和“ find ”:对集合应用判断式
- 别样的求和方式:sumBy、sum、fold、reduce
- 根据人的性别进行分组:groupBy
- 扁平化——处理嵌套集合:flatMap、flatten
- 惰性集合操作:序列
- 区间、数组、集合之间转换
- 面向对象
- 面向对象-封装
- 类的创建及属性方法访问
- 类属性和字段
- 构造器
- 嵌套类(内部类)
- 枚举类
- 枚举类遍历&枚举常量常用属性
- 数据类
- 密封类
- 印章类(密封类)
- 面向对象-继承
- 类的继承
- 面向对象-多态
- 抽象类
- 接口
- 接口和抽象类的区别
- 面向对象-深入
- 扩展
- 扩展:为别的类添加方法、属性
- Android中的扩展应用
- 优化Snackbar
- 用扩展函数封装Utils
- 解决烦人的findViewById
- 扩展不是万能的
- 调度方式对扩展函数的影响
- 被滥用的扩展函数
- 委托
- 委托类
- 委托属性
- Kotlin5大内置委托
- Kotlin-Object关键字
- 单例模式
- 匿名类对象
- 伴生对象
- 作用域函数
- let函数
- run函数
- with函数
- apply函数
- also函数
- 标准库函数
- takeIf 与 takeUnless
- 第二阶段重点深入
- Lambda编程
- Lambda成员引用高阶函数
- 高阶函数
- 内联函数
- 泛型
- 泛型的分类
- 泛型约束
- 子类和子类型
- 协变与逆变
- 泛型擦除与实化类型
- 泛型类型参数
- 泛型的背后:类型擦除
- Java为什么无法声明一个泛型数组
- 向后兼容的罪
- 类型擦除的矛盾
- 使用内联函数获取泛型
- 打破泛型不变
- 一个支持协变的List
- 一个支持逆变的Comparator
- 协变和逆变
- 第三阶段难点突破
- 注解和反射
- 声明并应用注解
- DSL
- 协程
- 协程简介
- 协程的基本操作
- 协程取消
- 管道
- 慕课霍丙乾协程笔记
- Kotlin与Java互操作
- 在Kotlin中调用Java
- 在Java中调用Kotlin
- Kotlin与Java中的操作对比
- 第四阶段专题练习
- 朱凯Kotlin知识点总结
- Kotlin 基础
- Kotlin 的变量、函数和类型
- Kotlin 里那些「不是那么写的」
- Kotlin 里那些「更方便的」
- Kotlin 进阶
- Kotlin 的泛型
- Kotlin 的高阶函数、匿名函数和 Lambda 表达式
- Kotlin协程
- 初识
- 进阶
- 深入
- Kotlin 扩展
- 会写「18.dp」只是个入门——Kotlin 的扩展函数和扩展属性(Extension Functions / Properties)
- Kotlin实战-开发Android