参考链接
Kotlin官方文档
https://kotlinlang.org/docs/home.html
中文网站
https://www.kotlincn.net/docs/reference/properties.html
pdf也可以在这里下载
https://www.kotlincn.net/docs/kotlin-docs.pdf
大部分示例来自bilibili Kotlin语言深入解析 张龙老师的视频
Part1
知识点
1 Kotlin属性 set get方法命名的变化
2 调用Kotlin成员方法
3 顶层空间的属性和方法属于静态方法
4 注意对比带Kt和不带Kt的类的使用
笔记
Kotlin class
/**
* 属性 (properties)
* 一个Kotlin的属性会被编译为3个部分
* 1.一个get方法
* 2.一个set方法
* 3.一个私有field域(field)
*
* 如果Kotlin的属性以is开头 那么set get方法会发生一些变化
* get方法方法名与属性名一致
* set方法会将is替换为set
* 这种规则适用于所有类型的属性 不一定时Boolean类型
*/
class Test{
var isStudent:String = "yes"
}
// 定义在顶层空间的属性和方法都是静态属性和方法
fun test1() {
println("test1")
}
var str: String = "hello"
class D0509JavaCallKotlin {
fun nonStaticMethod(){
println("nonStaticMethod")
}
}
Java class CallKotlin?????????
public class CallKotlin {
public static void main(String[] args) {
Test test = new Test();
// 1 Kotlin属性 set get方法命名的变化
test.setStudent("AAA");
System.out.println(test.isStudent());
System.out.println("--------- 1 end ----------");
// 2 调用Kotlin成员方法
// 注意 调用成员方法时使用D0509JavaCallKotlin
D0509JavaCallKotlin aa = new D0509JavaCallKotlin();
// D0509JavaCallKotlinKt bb = new D0509JavaCallKotlinKt();// 运行时报错 cannot find symbol
// 我们无法通过new关键字创建由Kotlin编译器生成的以Kt结尾的类的示例
// 因为在生成的字节码中 没有为以Kt结尾的类生成任何构造方法
// 反而是对应的没有以Kt结尾的类 是有构造方法的
aa.nonStaticMethod();
System.out.println("--------- 2 end ----------");
// 3 顶层空间的属性和方法属于静态方法
// 注意 调用时使用D0509Java3 @JvmField 修饰伴生对象的filedCallKotlinKt 而不是D0509JavaCallKotlin
D0509JavaCallKotlinKt.test1();
D0509JavaCallKotlinKt.setStr("set str");
System.out.println(D0509JavaCallKotlinKt.getStr());
System.out.println("--------- 3 end ----------");
// 4 注意对比带Kt和不带Kt的类的使用
// 即 D0509JavaCallKotlinKt 与 D0509JavaCallKotlin
}
}
Part2
知识点
1 元注解@file的使用
2 @JvmField的使用
3 @JvmField 修饰伴生对象的filed
4 @JvmStatic修饰伴生对象的方法
笔记
Kotlin code
// @file 注解代表期望将当前文件的生成文件从D0509JavaCallKotlin2 修改为HelloWorld1
@file: JvmMultifileClass
@file: JvmName("HelloWorld1")
package com.example.lib.d05others
fun myPrint(){
println("hello world1")
}
class D0509JavaCallKotlin2 {
}
// 1 元注解@file的使用
// 注解如果和D0509JavaCallKotlin2相同 且没有加 @file: JvmMultifileClass 则会报错
// e: D:\testDarren\LearnKotlin\StartKotlin\lib\src\main\java\com\example\lib\d05others\D0509JavaCallKotlin2.kt: (1, 1): Duplicate JVM class name 'com/example/lib/d05others/HelloWorld1' generated from: HelloWorld1, HelloWorld1
// 如果加上了 @file: JvmMultifileClass 则代表与其他叫HelloWorld1的文件进行合并
@file: JvmMultifileClass
@file: JvmName("HelloWorld1")
package com.example.lib.d05others
fun myPrint2() {
println("hello world2")
}
class MyPerson {
var name: String = "zhangsan"
// 2 @JvmField的使用
// @JvmField 会将普通的实例变量 变化成 类变量
// 即age1会变成一个静态变量 且没有set get方法
@JvmField
var age1: Int = 10
var age2: Int = 20
}
class MyPeople {
companion object {
var name = "zhangsan"
var age = 20
// 3 @JvmField 修饰伴生对象的filed
// age3变成伴生对象的类变量 没有了set get方法
@JvmField
var age3 = 30
// 4 @JvmStatic修饰伴生对象的方法
// 在Kotlin中 可以将剧名对象或者伴生对象中定义的函数注解为@JvmStatic 这样编译器会机会再相应对象的类中生成静态(类)方法 也会在在相应的类中生成实例方法
// 即 在companion对象中生成test1方法 在MyPeople也生成test1方法 且MyPeople.test1方法内部调用的是companion.test1
@JvmStatic
fun test1() {
println("test1")
}
fun test2() {
println("test2")
}
}
}
class D0509JavaCallKotlin3 {
}
Java code
package com.example.lib.d05others;
public class CallKotlin2 {
public static void main(String[] args) {
// JvmName修改了生成的字节码文件名
// 同时JvmMultifileClass可以合并不同字节码文件
// 虽然Kotlin有这个功能 但是非必要不推荐使用
HelloWorld1.myPrint();
HelloWorld1.myPrint2();
// JvmField使用使用在普通对象上
// Java 调用普通对象
MyPerson person = new MyPerson();
System.out.println(person.getName());
// age1变成了类变量
System.out.println(person.age1);
System.out.println(person.getAge2());
// Java 调用伴生对象
System.out.println(MyPeople.Companion.getAge());
System.out.println(MyPeople.Companion.getName());
// @JvmField加在伴生对象的属性上
System.out.println(MyPeople.age3);
MyPeople.Companion.test1();
// @JvmStatic加在伴生对象的方法上
MyPeople.test1();
MyPeople.Companion.test2();
}
}
Part3
知识点
1 JvmName注解 解决方法命名冲突
2 JvmName注解 解决方法命名冲突2
3 Java调用Kotlin带有默认参数的构造方法
4 Java调用Kotlin带有默认参数的普通方法
笔记
Kotlin code
package com.example.lib.d05others
/**
* 1 JvmName注解 解决方法命名冲突
*
* 由于类型擦除 (Java在生成的字节码文件中会抹去泛型信息) 以下两个方法在字节码的签名一致
* 因此报错
* Platform declaration clash: The following declarations have the same JVM signature
* (myFilter(Ljava/util/List;)Ljava/util/List;)
* 大意是 myFilter都接受一个List参数 返回一个List
* (为什么会接受一个List参数? 这是因为Java没有扩展方法的概念 Kotlin的扩展方法的实现原理是将类的实例传入,然后调用该实例的方法
* 因为这里是List的扩展方法 因此会将List实例作为参数传入扩展方法)
*
* 要想让这两个方法同时存在 可以使用 @JvmName注解
*/
fun List<String>.myFilter(): List<String> {
return listOf("hello", "world")
}
@JvmName("myFilter2")
fun List<Int>.myFilter(): List<Int> {
return listOf(1, 2, 3)
}
// 2 JvmName注解 解决方法命名冲突2
class MyClass {
val a: Int
/**
* Kotlin默认给属性a提供了get方法 签名为getA
* 因此如果另外又定义了getA方法 则会产生命名冲突
* 需要使用JvmName注解 将方法名改为另一个名字
* 但是注意 这里的JvmName还是给Java类用的 不影响Kotlin自身调用 a 属性
*/
@JvmName("getAValue")
get() = 20
fun getA() = 30
}
/**
* 3 Java调用Kotlin带有默认参数的构造方法
* 如果没有加上@JvmOverloads
* Java能调用的构造方法 只有两个参数的构造方法 无法省略参数
* 加上@JvmOverloads后 编译的文件会生成一个参数的构造方法 该方法内部调用了两个参数的构造方法
*/
class MyClass5 @JvmOverloads constructor(x: Int, y: String = "hello") {
// 4 Java调用Kotlin带有默认参数的普通方法
// JvmOverloads注解同样适用于普通方法
@JvmOverloads fun myMethod(a: Int, b: String, c: Int = 2) {
println("a:$a,b:$b,c:$c")
}
}
fun main() {
// 1 JvmName注解 解决方法命名冲突 示例
// 需要注意的是 这里的别名只给Java使用 在Kotlin中使用方法仍然应该使用myFilter而非myFilter2
val list = listOf<Int>()
println(list.myFilter())
val list2 = listOf<String>()
println(list2.myFilter())
// 2 JvmName注解 解决方法命名冲突2 示例
println(MyClass().getA())
// 注意 这里调用a的方式和Java不同
println(MyClass().a)
println(MyClass5(1))
}
class D0509JavaCallKotlin4 {
}
Java code
package com.example.lib.d05others;
import java.util.ArrayList;
import java.util.List;
public class CallKotlin3 {
public static void main(String[] args) {
// 1 JvmName注解 解决方法命名冲突
List<String> list = D0509JavaCallKotlin4Kt.myFilter(new ArrayList<String>());
System.out.println(list);
List<Integer> list2 = D0509JavaCallKotlin4Kt.myFilter2(new ArrayList<Integer>());
System.out.println(list2);
// 2 JvmName注解 解决方法命名冲突2
MyClass myClass = new MyClass();
System.out.println(myClass.getA());
System.out.println(myClass.getAValue());
// 3 Java调用Kotlin带有默认参数的构造方法
MyClass5 myClass5 = new MyClass5(1,"string");
// Java看起来也可以使用默认参数了
MyClass5 myClass51 = new MyClass5(1);
// 4 Java调用Kotlin带有默认参数的普通方法
myClass5.myMethod(1,"string");
myClass5.myMethod(1,"string",2);
}
}
Part4
知识点
1 Java调用Kotlin抛出检查时异常的方法
2 Java调用Kotlin抛出检查时异常的方法(Java不异常终止)
3 Java调用Kotlin时 空保护失效
笔记
Kotlin code
package com.example.lib.d05others
import java.io.FileNotFoundException
import kotlin.jvm.Throws
class D0509JavaCallKotlin5 {
/**
* 1 Java调用Kotlin抛出检查时异常的方法
* 因为Kotlin没有checked exception 因此Java调用该方法时 认为该方法是普通方法
* 可以直接调用 然而却在运行时抛出异常 且method invoked 都不会输出
*/
fun method(){
println("method invoked")
throw FileNotFoundException("file not found")
}
/**
* 2 Java调用Kotlin抛出检查时异常的方法(Java不异常终止)
* @Throws 注解告诉Java文件 该方法会抛出异常
*/
@Throws(FileNotFoundException::class)
fun method2(){
println("method invoked")
throw FileNotFoundException("my file not found")
}
/**
* 3 Java调用Kotlin时 空保护失效
* 这里str在Kotlin明显是一个非空的string
* 然而Java调用时并不知道这一点
* 如果直接传入空 会被Kotlin在判空检查时就检查出来 因此method3 invoked都不会输出 直接抛出异常
*/
fun method3(str:String){
println("method3 invoked")
println(str)
}
}
Java code
import java.io.FileNotFoundException;
public class CallKotlin4 {
public static void main(String[] args) {
D0509JavaCallKotlin5 kotlin5 = new D0509JavaCallKotlin5();
// kotlin5.method();// 运行时报错
// 因为加了@Throws注解 Java调用时知道该方法可能抛出异常
try {
kotlin5.method2();
} catch (FileNotFoundException e) {
System.out.println("catch FileNotFoundException "+e.getMessage());
}
kotlin5.method3("hello");
// kotlin5.method3(null); //运行直接报错
}
}
|