0
点赞
收藏
分享

微信扫一扫

【Kotlin】常用的 Kotlin 类 ① ( 嵌套类 | 数据类 | 数据类 copy 函数 | 数据类解构声明 operator fun component1 | 数据类运算符重载 )


文章目录

  • ​​一、嵌套类​​
  • ​​二、数据类​​
  • ​​三、数据类 copy 函数​​
  • ​​四、数据类解构声明​​
  • ​​1、Kotlin 普通类解构声明 operator fun component1​​
  • ​​2、数据类解构声明​​
  • ​​五、运算符重载函数​​






一、嵌套类


嵌套类 指的是 在 类 A 中 定义 类 B

class A {
class B {
}
}

在 类 A 中调用 B , 可以直接使用 B() 进行调用 ;

在 外部调用 类 B 时 , 可以使用 A.B() 的形式进行调用 ;



在 Java 中内部类有 成员内部类 , 静态嵌套类 , 方法内部类 , 匿名内部类 几种类型 ;

Kotlin 嵌套类 , 相当于 Java 中的 静态嵌套类 ;



代码示例 : 在下面的代码中 , 在 Person 类内部中定义 Student 嵌套类 , 在 外部使用 Person.Student 使用其内部的 Student 嵌套类 ;

open class Person(val name: String, val age: Int) {
class Student(val school: String) {
fun goSchool() {
println("去 ${school} 上学")
}
}
}

fun main() {
Person.Student("小学").goSchool()
}

执行结果 :

去 小学 上学






二、数据类


数据类型定义 : Kotlin 中的 数据类型 是 专门用于存储 数据的 类

数据类信息 : 数据类 中 自动提供了 toString 实现

数据类型对比 : == 运算符 对比两个数数据类对比的是引用地址 , equals 和 hashCode 函数 可以对比具体的数据值 ;



在 Kotlin 中 , 一般情况下 == 比较的是内容 , === 比较的是引用 ;

== 运算符相当于调用的是 equals 方法 , 只要重写了 equals 方法 , == 比较的就是内容 ;

在 Any 超类中 , 没有重写 equals 方法 , == 对比的是 引用地址 ;



数据类定义形式 :

data class 数据类类名(数据类型参数) {}



代码示例 :

data class Student(var name: String, var age: Int)

fun main() {
println(Student("Tom", 18))

// 在 Kotlin 中 , 一般情况下 == 比较的是内容 , === 比较的是引用
println(Student("Tom", 18) == Student("Tom", 18))
}

执行结果 : 定义上述数据类 , 打印该数据类实例对象 , 得到的不是地址信息 , 而是数据类的实际值 ;

Student(name=Tom, age=18)
true

查看字节码信息 , 双击 Shift , 选择 Show Kotlin Bytecode 选项 ,

【Kotlin】常用的 Kotlin 类 ① ( 嵌套类 | 数据类 | 数据类 copy 函数 | 数据类解构声明 operator fun component1 | 数据类运算符重载 )_kotlin

在 Kotlin Bytecode 界面 中 , 选择 Decompile 选项 , 将 字节码数据 反编译为 Java 代码数据 ,

【Kotlin】常用的 Kotlin 类 ① ( 嵌套类 | 数据类 | 数据类 copy 函数 | 数据类解构声明 operator fun component1 | 数据类运算符重载 )_数据类_02

发现 Kotlin 编译器 为 Student 数据类 自动生成了一个 toString 方法

同时还 重写 Student 数据类 中的 equals 和 hashCode 函数 ;

// Student.java
import kotlin.Metadata;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

@Metadata(
mv = {1, 4, 2},
bv = {1, 0, 3},
k = 1,
d1 = {"\u0000 \n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0000\n\u0002\u0010\u000e\n\u0000\n\u0002\u0010\b\n\u0002\b\r\n\u0002\u0010\u000b\n\u0002\b\u0004\b\u0086\b\u0018\u00002\u00020\u0001B\u0015\u0012\u0006\u0010\u0002\u001a\u00020\u0003\u0012\u0006\u0010\u0004\u001a\u00020\u0005¢\u0006\u0002\u0010\u0006J\t\u0010\u000f\u001a\u00020\u0003HÆ\u0003J\t\u0010\u0010\u001a\u00020\u0005HÆ\u0003J\u001d\u0010\u0011\u001a\u00020\u00002\b\b\u0002\u0010\u0002\u001a\u00020\u00032\b\b\u0002\u0010\u0004\u001a\u00020\u0005HÆ\u0001J\u0013\u0010\u0012\u001a\u00020\u00132\b\u0010\u0014\u001a\u0004\u0018\u00010\u0001HÖ\u0003J\t\u0010\u0015\u001a\u00020\u0005HÖ\u0001J\t\u0010\u0016\u001a\u00020\u0003HÖ\u0001R\u001a\u0010\u0004\u001a\u00020\u0005X\u0086\u000e¢\u0006\u000e\n\u0000\u001a\u0004\b\u0007\u0010\b\"\u0004\b\t\u0010\nR\u001a\u0010\u0002\u001a\u00020\u0003X\u0086\u000e¢\u0006\u000e\n\u0000\u001a\u0004\b\u000b\u0010\f\"\u0004\b\r\u0010\u000e¨\u0006\u0017"},
d2 = {"LStudent;", "", "name", "", "age", "", "(Ljava/lang/String;I)V", "getAge", "()I", "setAge", "(I)V", "getName", "()Ljava/lang/String;", "setName", "(Ljava/lang/String;)V", "component1", "component2", "copy", "equals", "", "other", "hashCode", "toString", "KotlinDemo"}
)
public final class Student {
@NotNull
private String name;
private int age;

@NotNull
public final String getName() {
return this.name;
}

public final void setName(@NotNull String var1) {
Intrinsics.checkNotNullParameter(var1, "<set-?>");
this.name = var1;
}

public final int getAge() {
return this.age;
}

public final void setAge(int var1) {
this.age = var1;
}

public Student(@NotNull String name, int age) {
Intrinsics.checkNotNullParameter(name, "name");
super();
this.name = name;
this.age = age;
}

@NotNull
public final String component1() {
return this.name;
}

public final int component2() {
return this.age;
}

@NotNull
public final Student copy(@NotNull String name, int age) {
Intrinsics.checkNotNullParameter(name, "name");
return new Student(name, age);
}

// $FF: synthetic method
public static Student copy$default(Student var0, String var1, int var2, int var3, Object var4) {
if ((var3 & 1) != 0) {
var1 = var0.name;
}

if ((var3 & 2) != 0) {
var2 = var0.age;
}

return var0.copy(var1, var2);
}

@NotNull
public String toString() {
return "Student(name=" + this.name + ", age=" + this.age + ")";
}

public int hashCode() {
String var10000 = this.name;
return (var10000 != null ? var10000.hashCode() : 0) * 31 + this.age;
}

public boolean equals(@Nullable Object var1) {
if (this != var1) {
if (var1 instanceof Student) {
Student var2 = (Student)var1;
if (Intrinsics.areEqual(this.name, var2.name) && this.age == var2.age) {
return true;
}
}

return false;
} else {
return true;
}
}
}
// HelloKt.java
import kotlin.Metadata;

@Metadata(
mv = {1, 4, 2},
bv = {1, 0, 3},
k = 2,
d1 = {"\u0000\b\n\u0000\n\u0002\u0010\u0002\n\u0000\u001a\u0006\u0010\u0000\u001a\u00020\u0001¨\u0006\u0002"},
d2 = {"main", "", "KotlinDemo"}
)
public final class HelloKt {
public static final void main() {
Student var0 = new Student("Tom", 18);
boolean var1 = false;
System.out.println(var0);
}

// $FF: synthetic method
public static void main(String[] var0) {
main();
}
}






三、数据类 copy 函数


Kotlin 编译器不仅为 数据类 重写了 toString , equals , hashCode 函数 , 还 提供了 copy 函数 , 借助该函数可以 快速创建一个相同内容的数据类 ;

特别注意 : 数据类 copy 函数调用的是主构造函数 , 如果数据类有属性是在次构造函数中赋值的 , 则该数据不会被 copy 函数复制 ;

在上个章节查看的 数据类 字节码 反编译后的 Java 代码 , 查看其 copy 函数 , 内容如下 :

// $FF: synthetic method
public static Student copy$default(Student var0, String var1, int var2, int var3, Object var4) {
if ((var3 & 1) != 0) {
var1 = var0.name;
}

if ((var3 & 2) != 0) {
var2 = var0.age;
}

return var0.copy(var1, var2);
}



代码示例 :

data class Student(var name: String, var age: Int)

fun main() {
val student = Student("Tom", 18)
println(student)

// 拷贝数据类, name 属性设置为 Jerry
val student2 = student.copy(name = "Jerry")
println(student2)
}

执行结果 :

Student(name=Tom, age=18)
Student(name=Jerry, age=18)






四、数据类解构声明


在之前的博客 ​​【Kotlin】集合操作 ③ ( List 集合遍历 | for in | forEach | forEachIndexed | List 通过解构一次性给多个元素赋值 )​​ 中介绍了 , 使用集合一次性给多个变量赋值 ;

Kotlin 普通类 和 数据类 都可以 支持 解构语法 , 为多个变量进行赋值 ;

数据类 自带 支持解构语法的特性 , 不需要使用 operator fun component1() 解构声明 ;



1、Kotlin 普通类解构声明 operator fun component1



在 普通 Kotlin 类中使用 如下声明 , 即可支持解构语法 ;

operator fun component1() = 成员属性名1
operator fun component2() = 成员属性名2
operator fun component3() = 成员属性名3
operator fun component4() = 成员属性名4
...
...



代码示例 :

class Student(var name: String, var age: Int) {
operator fun component1() = name
operator fun component2() = age
}

fun main() {
val student = Student("Tom", 18)
println(student)

val (name, age) = student
println("name = $name, age = $age")
}

执行结果 :

Student@61bbe9ba
name = Tom, age = 18



2、数据类解构声明



数据类 自带 支持解构语法的特性 , 不需要使用 operator fun component1() 解构声明 ;



代码示例 :

data class Student(var name: String, var age: Int)

fun main() {
val student = Student("Tom", 18)
println(student)

val (name, age) = student
println("name = $name, age = $age")
}

执行结果 :

Student(name=Tom, age=18)
name = Tom, age = 18

查看字节码信息 , 双击 Shift , 选择 Show Kotlin Bytecode 选项 ,

【Kotlin】常用的 Kotlin 类 ① ( 嵌套类 | 数据类 | 数据类 copy 函数 | 数据类解构声明 operator fun component1 | 数据类运算符重载 )_kotlin

在 Kotlin Bytecode 界面 中 , 选择 Decompile 选项 , 将 字节码数据 反编译为 Java 代码数据 ,

【Kotlin】常用的 Kotlin 类 ① ( 嵌套类 | 数据类 | 数据类 copy 函数 | 数据类解构声明 operator fun component1 | 数据类运算符重载 )_数据类_02

反编译后的 Java 代码数据如下 :

// Student.java
import kotlin.Metadata;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

@Metadata(
mv = {1, 4, 2},
bv = {1, 0, 3},
k = 1,
d1 = {"\u0000 \n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0000\n\u0002\u0010\u000e\n\u0000\n\u0002\u0010\b\n\u0002\b\r\n\u0002\u0010\u000b\n\u0002\b\u0004\b\u0086\b\u0018\u00002\u00020\u0001B\u0015\u0012\u0006\u0010\u0002\u001a\u00020\u0003\u0012\u0006\u0010\u0004\u001a\u00020\u0005¢\u0006\u0002\u0010\u0006J\t\u0010\u000f\u001a\u00020\u0003HÆ\u0003J\t\u0010\u0010\u001a\u00020\u0005HÆ\u0003J\u001d\u0010\u0011\u001a\u00020\u00002\b\b\u0002\u0010\u0002\u001a\u00020\u00032\b\b\u0002\u0010\u0004\u001a\u00020\u0005HÆ\u0001J\u0013\u0010\u0012\u001a\u00020\u00132\b\u0010\u0014\u001a\u0004\u0018\u00010\u0001HÖ\u0003J\t\u0010\u0015\u001a\u00020\u0005HÖ\u0001J\t\u0010\u0016\u001a\u00020\u0003HÖ\u0001R\u001a\u0010\u0004\u001a\u00020\u0005X\u0086\u000e¢\u0006\u000e\n\u0000\u001a\u0004\b\u0007\u0010\b\"\u0004\b\t\u0010\nR\u001a\u0010\u0002\u001a\u00020\u0003X\u0086\u000e¢\u0006\u000e\n\u0000\u001a\u0004\b\u000b\u0010\f\"\u0004\b\r\u0010\u000e¨\u0006\u0017"},
d2 = {"LStudent;", "", "name", "", "age", "", "(Ljava/lang/String;I)V", "getAge", "()I", "setAge", "(I)V", "getName", "()Ljava/lang/String;", "setName", "(Ljava/lang/String;)V", "component1", "component2", "copy", "equals", "", "other", "hashCode", "toString", "KotlinDemo"}
)
public final class Student {
@NotNull
private String name;
private int age;

@NotNull
public final String getName() {
return this.name;
}

public final void setName(@NotNull String var1) {
Intrinsics.checkNotNullParameter(var1, "<set-?>");
this.name = var1;
}

public final int getAge() {
return this.age;
}

public final void setAge(int var1) {
this.age = var1;
}

public Student(@NotNull String name, int age) {
Intrinsics.checkNotNullParameter(name, "name");
super();
this.name = name;
this.age = age;
}

@NotNull
public final String component1() {
return this.name;
}

public final int component2() {
return this.age;
}

@NotNull
public final Student copy(@NotNull String name, int age) {
Intrinsics.checkNotNullParameter(name, "name");
return new Student(name, age);
}

// $FF: synthetic method
public static Student copy$default(Student var0, String var1, int var2, int var3, Object var4) {
if ((var3 & 1) != 0) {
var1 = var0.name;
}

if ((var3 & 2) != 0) {
var2 = var0.age;
}

return var0.copy(var1, var2);
}

@NotNull
public String toString() {
return "Student(name=" + this.name + ", age=" + this.age + ")";
}

public int hashCode() {
String var10000 = this.name;
return (var10000 != null ? var10000.hashCode() : 0) * 31 + this.age;
}

public boolean equals(@Nullable Object var1) {
if (this != var1) {
if (var1 instanceof Student) {
Student var2 = (Student)var1;
if (Intrinsics.areEqual(this.name, var2.name) && this.age == var2.age) {
return true;
}
}

return false;
} else {
return true;
}
}
}
// HelloKt.java
import kotlin.Metadata;

@Metadata(
mv = {1, 4, 2},
bv = {1, 0, 3},
k = 2,
d1 = {"\u0000\b\n\u0000\n\u0002\u0010\u0002\n\u0000\u001a\u0006\u0010\u0000\u001a\u00020\u0001¨\u0006\u0002"},
d2 = {"main", "", "KotlinDemo"}
)
public final class HelloKt {
public static final void main() {
Student student = new Student("Tom", 18);
boolean var1 = false;
System.out.println(student);
String name = student.component1();
int age = student.component2();
String var3 = "name = " + name + ", age = " + age;
boolean var4 = false;
System.out.println(var3);
}

// $FF: synthetic method
public static void main(String[] var0) {
main();
}
}

关注 数据类 Student 的结构声明 , Kotlin 编译器在编译时自动给数据类添加上了结构声明 ;

@NotNull
public final String component1() {
return this.name;
}

public final int component2() {
return this.age;
}






五、运算符重载函数


下图是 Kotlin 运算符重载操作符对应的函数名 :

【Kotlin】常用的 Kotlin 类 ① ( 嵌套类 | 数据类 | 数据类 copy 函数 | 数据类解构声明 operator fun component1 | 数据类运算符重载 )_运算符重载_05

如果需要 为类添加 + 操作符 支持 , 则 需要在类中设置 plus 运算符重载函数 ;



运算符重载函数定义 :

operator fun plus(t: T): T



代码示例 :

data class Student(var name: String, var age: Int) {
operator fun plus(other: Student): Student {
return Student("$name, ${other.name}", age + other.age)
}
}

fun main() {
val student = Student("Tom", 18)
val student2 = Student("Jerry", 12)
println(student + student2)
}

执行结果 :

Student(name=Tom, Jerry, age=30)


举报

相关推荐

0 条评论