kotlin学习(四)-面向对象

  

  • 写在本文之前:
      本文中会用到kotlin转java代码,所以这里附上使用intellij IDEA将kotlin转成java的方法:在idea中选中要查看的文件,在菜单栏中点击tools,找到kotlin,点击kotlin找到show kotlin bytecode,点击后会在窗口右边显示字节码,在字节码窗口的左上角有一个decompile,点击decompile就可以反编译成java代码

kotlin的面向对象在java的基础上做了很大的优化

  • 访问器
    在面向对象中,很多场景我们会对属性做一些限制,比如对某个属性只允许访问,不准修改,还有在对一些属性进行赋值时会进行一些校验

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    fun main(arg: Array<String>) {
    var h = Human()
    println(h.name)
    println(h.age)
    // h.name = "李四"
    h.age = 20
    println(h.name)
    println(h.age)

    }

    class Human(){
    var name:String = "张三"
    private set

    var age: Int = 18
    set(value) {
    if (value < 200) {
    // this.age = value
    field = value
    }
    }
    }

    比如在这个例子中,我们要求不允许对象对name字段进行修改,那么只需要在属性下一行紧跟着使用private set,就可以将禁止对该属性进行修改,对age字段我们允许对象进行修改,但是要求年龄不允许超过200岁,所以重写在age字段后面重写set方法,就可以在赋值的时候进行一些预校验,这里需要强调的时候在set方法内,不要使用this来赋值,否则会栈溢出
    通过kotlin字节码反编译成java代码,我们可以发现,在kotlin中定义的属性,会在转化成java时默认加上private权限,同时定义get和set方法,我们使用private修饰set后反编译成 Java,可以知道这相当于给set方法加了一个private属性,具体请看下面反编译生成java代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    // TestKt.java
    import kotlin.Metadata;
    import kotlin.jvm.internal.Intrinsics;
    import org.jetbrains.annotations.NotNull;

    @Metadata(
    mv = {1, 1, 13},
    bv = {1, 0, 3},
    k = 2,
    d1 = {"\u0000\u0014\n\u0000\n\u0002\u0010\u0002\n\u0000\n\u0002\u0010\u0011\n\u0002\u0010\u000e\n\u0002\b\u0002\u001a\u0019\u0010\u0000\u001a\u00020\u00012\f\u0010\u0002\u001a\b\u0012\u0004\u0012\u00020\u00040\u0003¢\u0006\u0002\u0010\u0005¨\u0006\u0006"},
    d2 = {"main", "", "arg", "", "", "([Ljava/lang/String;)V", "kotlin_practice"}
    )
    public final class TestKt {
    public static final void main(@NotNull String[] arg) {
    Intrinsics.checkParameterIsNotNull(arg, "arg");
    Human h = new Human();
    String var2 = h.getName();
    System.out.println(var2);
    int var3 = h.getAge();
    System.out.println(var3);
    h.setAge(20);
    var2 = h.getName();
    System.out.println(var2);
    var3 = h.getAge();
    System.out.println(var3);
    }
    }
    // Human.java
    import kotlin.Metadata;
    import org.jetbrains.annotations.NotNull;

    @Metadata(
    mv = {1, 1, 13},
    bv = {1, 0, 3},
    k = 1,
    d1 = {"\u0000\u001c\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\n\u0002\u0010\b\n\u0002\b\u0006\n\u0002\u0010\u000e\n\u0002\b\u0006\u0018\u00002\u00020\u0001B\u0005¢\u0006\u0002\u0010\u0002R$\u0010\u0005\u001a\u00020\u00042\u0006\u0010\u0003\u001a\u00020\u0004@FX\u0086\u000e¢\u0006\u000e\n\u0000\u001a\u0004\b\u0006\u0010\u0007\"\u0004\b\b\u0010\tR$\u0010\f\u001a\u00020\u000b2\u0006\u0010\n\u001a\u00020\u000b@BX\u0086\u000e¢\u0006\u000e\n\u0000\u001a\u0004\b\r\u0010\u000e\"\u0004\b\u000f\u0010\u0010¨\u0006\u0011"},
    d2 = {"LHuman;", "", "()V", "value", "", "age", "getAge", "()I", "setAge", "(I)V", "<set-?>", "", "name", "getName", "()Ljava/lang/String;", "setName", "(Ljava/lang/String;)V", "kotlin_practice"}
    )
    public final class Human {
    @NotNull
    private String name = "张三";
    private int age = 18;

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

    private final void setName(String var1) {
    this.name = var1;
    }

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

    public final void setAge(int value) {
    if (value < 200) {
    this.age = value;
    }

    }
    }
  • init方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    fun main(arg: Array<String>) {
    var h = Human("李四", 23)
    println(h.name)
    println(h.age)
    }

    class Human(name: String, age: Int){
    var name: String = ""
    var age: Int = 0
    init {
    this.name = name
    this.age = age
    }
    }

    init定义的是构造方法,这里面的逻辑最终会编译到java的构造函数中

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    // TestKt.java
    import kotlin.Metadata;
    import kotlin.jvm.internal.Intrinsics;
    import org.jetbrains.annotations.NotNull;

    @Metadata(
    mv = {1, 1, 13},
    bv = {1, 0, 3},
    k = 2,
    d1 = {"\u0000\u0014\n\u0000\n\u0002\u0010\u0002\n\u0000\n\u0002\u0010\u0011\n\u0002\u0010\u000e\n\u0002\b\u0002\u001a\u0019\u0010\u0000\u001a\u00020\u00012\f\u0010\u0002\u001a\b\u0012\u0004\u0012\u00020\u00040\u0003¢\u0006\u0002\u0010\u0005¨\u0006\u0006"},
    d2 = {"main", "", "arg", "", "", "([Ljava/lang/String;)V", "kotlin_practice"}
    )
    public final class TestKt {
    public static final void main(@NotNull String[] arg) {
    Intrinsics.checkParameterIsNotNull(arg, "arg");
    Human h = new Human("李四", 23);
    String var2 = h.getName();
    System.out.println(var2);
    int var3 = h.getAge();
    System.out.println(var3);
    }
    }
    // Human.java
    import kotlin.Metadata;
    import kotlin.jvm.internal.Intrinsics;
    import org.jetbrains.annotations.NotNull;

    @Metadata(
    mv = {1, 1, 13},
    bv = {1, 0, 3},
    k = 1,
    d1 = {"\u0000\u0018\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0000\n\u0002\u0010\u000e\n\u0000\n\u0002\u0010\b\n\u0002\b\n\u0018\u00002\u00020\u0001B\u0015\u0012\u0006\u0010\u0002\u001a\u00020\u0003\u0012\u0006\u0010\u0004\u001a\u00020\u0005¢\u0006\u0002\u0010\u0006R\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\u000f"},
    d2 = {"LHuman;", "", "name", "", "age", "", "(Ljava/lang/String;I)V", "getAge", "()I", "setAge", "(I)V", "getName", "()Ljava/lang/String;", "setName", "(Ljava/lang/String;)V", "kotlin_practice"}
    )
    public final class Human {
    @NotNull
    private String name;
    private int age;

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

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

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

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

    public Human(@NotNull String name, int age) {
    Intrinsics.checkParameterIsNotNull(name, "name");
    super();
    this.name = "";
    this.name = name;
    this.age = age;
    }
    }
  • 使用var和val的方式定义构造方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    fun main(arg: Array<String>) {
    var h = Human("李四", 23)
    println(h.name)
    println(h.age)
    // h.name = "ss"
    h.age = 24
    println(h.age)
    }

    class Human(val name: String, var age: Int){

    }

    这段代码中定义类只用了一行代码,但它和上面的代码有同样的效果,即name不可修改,age可修改
    只不过通过查看反编译后的java代码可以发现,这和private set还是有区别的,privata是将set方法设置为私有,而val定义的方式不会生成set方法,因为属性是私有的,所有同样可以起到不允许修改的作用

  • 次构造方法(构造方法重载)
    在我的理解看来kotlin的次构造方法就相当于java的构造方法重载,kotlin次构造函数使用方法如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    fun main(arg: Array<String>) {
    var h = Human("李四", 23)
    println(h.name)
    println(h.age)
    println(h.phone)
    // h.name = "ss"
    h.age = 24
    println(h.age)
    var h1 = Human("王五", 40, "13788888888")
    println(h1.name)
    println(h1.age)
    println(h1.phone)
    }

    class Human(val name: String, var age: Int){
    var phone: String = ""
    constructor(name:String,age:Int,phone:String):this(name, age){
    this.phone = phone
    }
    }

    constructor就是定义次构造函数的关键词
    查看对应的java代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    // TestKt.java
    import kotlin.Metadata;
    import kotlin.jvm.internal.Intrinsics;
    import org.jetbrains.annotations.NotNull;

    @Metadata(
    mv = {1, 1, 13},
    bv = {1, 0, 3},
    k = 2,
    d1 = {"\u0000\u0014\n\u0000\n\u0002\u0010\u0002\n\u0000\n\u0002\u0010\u0011\n\u0002\u0010\u000e\n\u0002\b\u0002\u001a\u0019\u0010\u0000\u001a\u00020\u00012\f\u0010\u0002\u001a\b\u0012\u0004\u0012\u00020\u00040\u0003¢\u0006\u0002\u0010\u0005¨\u0006\u0006"},
    d2 = {"main", "", "arg", "", "", "([Ljava/lang/String;)V", "kotlin_practice"}
    )
    public final class TestKt {
    public static final void main(@NotNull String[] arg) {
    Intrinsics.checkParameterIsNotNull(arg, "arg");
    Human h = new Human("李四", 23);
    String var2 = h.getName();
    System.out.println(var2);
    int var4 = h.getAge();
    System.out.println(var4);
    var2 = h.getPhone();
    System.out.println(var2);
    h.setAge(24);
    var4 = h.getAge();
    System.out.println(var4);
    Human h1 = new Human("王五", 40, "13788888888");
    String var3 = h1.getName();
    System.out.println(var3);
    int var6 = h1.getAge();
    System.out.println(var6);
    var3 = h1.getPhone();
    System.out.println(var3);
    }
    }
    // Human.java
    import kotlin.Metadata;
    import kotlin.jvm.internal.Intrinsics;
    import org.jetbrains.annotations.NotNull;

    @Metadata(
    mv = {1, 1, 13},
    bv = {1, 0, 3},
    k = 1,
    d1 = {"\u0000\u0018\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0000\n\u0002\u0010\u000e\n\u0000\n\u0002\u0010\b\n\u0002\b\r\u0018\u00002\u00020\u0001B\u001f\b\u0016\u0012\u0006\u0010\u0002\u001a\u00020\u0003\u0012\u0006\u0010\u0004\u001a\u00020\u0005\u0012\u0006\u0010\u0006\u001a\u00020\u0003¢\u0006\u0002\u0010\u0007B\u0015\u0012\u0006\u0010\u0002\u001a\u00020\u0003\u0012\u0006\u0010\u0004\u001a\u00020\u0005¢\u0006\u0002\u0010\bR\u001a\u0010\u0004\u001a\u00020\u0005X\u0086\u000e¢\u0006\u000e\n\u0000\u001a\u0004\b\t\u0010\n\"\u0004\b\u000b\u0010\fR\u0011\u0010\u0002\u001a\u00020\u0003¢\u0006\b\n\u0000\u001a\u0004\b\r\u0010\u000eR\u001a\u0010\u0006\u001a\u00020\u0003X\u0086\u000e¢\u0006\u000e\n\u0000\u001a\u0004\b\u000f\u0010\u000e\"\u0004\b\u0010\u0010\u0011¨\u0006\u0012"},
    d2 = {"LHuman;", "", "name", "", "age", "", "phone", "(Ljava/lang/String;ILjava/lang/String;)V", "(Ljava/lang/String;I)V", "getAge", "()I", "setAge", "(I)V", "getName", "()Ljava/lang/String;", "getPhone", "setPhone", "(Ljava/lang/String;)V", "kotlin_practice"}
    )
    public final class Human {
    @NotNull
    private String phone;
    @NotNull
    private final String name;
    private int age;

    @NotNull
    public final String getPhone() {
    return this.phone;
    }

    public final void setPhone(@NotNull String var1) {
    Intrinsics.checkParameterIsNotNull(var1, "<set-?>");
    this.phone = var1;
    }

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

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

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

    public Human(@NotNull String name, int age) {
    Intrinsics.checkParameterIsNotNull(name, "name");
    super();
    this.name = name;
    this.age = age;
    this.phone = "";
    }

    public Human(@NotNull String name, int age, @NotNull String phone) {
    Intrinsics.checkParameterIsNotNull(name, "name");
    Intrinsics.checkParameterIsNotNull(phone, "phone");
    this(name, age);
    this.phone = phone;
    }
    }

    从Java代码最后的两个构造方法可以看出,constructor其实就是定义了构造函数的重载

  • init 和constructor的执行顺序
    init先于constructor执行

-------------本文结束感谢您的阅读-------------

本文标题:kotlin学习(四)-面向对象

文章作者:fengxi

发布时间:2019年01月23日 - 14:01

最后更新:2019年04月04日 - 21:04

原始链接:https://super-storm.github.io/2019/01/23/kotlin学习(四)-面向对象/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。