美文网首页Kotlin
Kotlin基础(3)-类

Kotlin基础(3)-类

作者: 取了个很好听的名字 | 来源:发表于2019-11-01 12:00 被阅读0次

前言

本文主要介绍Kotlin中类的创建以及使用

定义类

kotlin中定义类的方式如下:

class A  (){
    

}

class 声明其是一个类,A代表类名,{}代表类体
Java字节码如下:

@Metadata(
   mv = {1, 1, 10},
   bv = {1, 0, 2},
   k = 1,
   d1 = {"\u0000\f\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\u0018\u00002\u00020\u0001B\u0005¢\u0006\u0002\u0010\u0002¨\u0006\u0003"},
   d2 = {"Lcom/zhqy/javademo/A;", "", "()V", "production sources for module app"}
)
public final class A {
}

可以看出类默认被final修饰,不可以被修改继承,如果想被其他类继承可以使用open关键字

open class A  (){


}

java字节码如下

@Metadata(
   mv = {1, 1, 10},
   bv = {1, 0, 2},
   k = 1,
   d1 = {"\u0000\f\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\b\u0016\u0018\u00002\u00020\u0001B\u0005¢\u0006\u0002\u0010\u0002¨\u0006\u0003"},
   d2 = {"Lcom/zhqy/javademo/A;", "", "()V", "production sources for module app"}
)
public class A {
}

如果想要限定类的作用范围可以使用可见性修饰符进行限定


可见性修饰符.png

代码如下:

 private class A  (){


}

Java 字节码

@Metadata(
   mv = {1, 1, 10},
   bv = {1, 0, 2},
   k = 1,
   d1 = {"\u0000\f\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\b\u0002\u0018\u00002\u00020\u0001B\u0005¢\u0006\u0002\u0010\u0002¨\u0006\u0003"},
   d2 = {"Lcom/zhqy/javademo/A;", "", "()V", "production sources for module app"}
)
final class A {
}

构造方法

Kotlin中有一个主构造的说法,即创建这个类的构造方法,而构造方法的重载成为二级构造器,所有的二级构造器都直接或间接的使用主构造器。主构造器的创建如下:

 private class A(var name:String,var age:Int ){
    
}

在括号中添加需要传递进来的数据来构造类对象。
java字节码如下:

@Metadata(
   mv = {1, 1, 10},
   bv = {1, 0, 2},
   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\b\u0002\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 = {"Lcom/zhqy/javademo/A;", "", "name", "", "age", "", "(Ljava/lang/String;I)V", "getAge", "()I", "setAge", "(I)V", "getName", "()Ljava/lang/String;", "setName", "(Ljava/lang/String;)V", "production sources for module app"}
)
final class A {
   @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 A(@NotNull String name, int age) {
      Intrinsics.checkParameterIsNotNull(name, "name");
      super();
      this.name = name;
      this.age = age;
   }
}

可以看见类中声明了成员变量和get,set方法,也就是说传递进来的参数会被添加到成员变量中并提供get和set方法。如果不想这样做的话可以去掉var关键字

 private class A( name:String, age:Int ){

}

java字节码如下:

@Metadata(
   mv = {1, 1, 10},
   bv = {1, 0, 2},
   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\u0002\b\u0002\u0018\u00002\u00020\u0001B\u0015\u0012\u0006\u0010\u0002\u001a\u00020\u0003\u0012\u0006\u0010\u0004\u001a\u00020\u0005¢\u0006\u0002\u0010\u0006¨\u0006\u0007"},
   d2 = {"Lcom/zhqy/javademo/A;", "", "name", "", "age", "", "(Ljava/lang/String;I)V", "production sources for module app"}
)
final class A {
   public A(@NotNull String name, int age) {
      Intrinsics.checkParameterIsNotNull(name, "name");
      super();
   }
}

不过这显然是没有意义的,也不推荐这样做。
那么如何在构造方法中添加代码实现响应功能呢?kotlin提供了init代码块来解决该问题

 private class A(var name:String, var age:Int ){
   init {
        println("我在主构造方法中1");
    }

    init {
        println("我在主构造方法中2");
    }
}

java字节码

@Metadata(
   mv = {1, 1, 10},
   bv = {1, 0, 2},
   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\b\u0002\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 = {"Lcom/zhqy/javademo/A;", "", "name", "", "age", "", "(Ljava/lang/String;I)V", "getAge", "()I", "setAge", "(I)V", "getName", "()Ljava/lang/String;", "setName", "(Ljava/lang/String;)V", "production sources for module app"}
)
final class A {
   @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 A(@NotNull String name, int age) {
      Intrinsics.checkParameterIsNotNull(name, "name");
      super();
      this.name = name;
      this.age = age;
      String var3 = "我在主构造方法中1";
      System.out.println(var3);
      var3 = "我在主构造方法中2";
      System.out.println(var3);
   }
}

在Java字节码中添加了两条打印信息,而且打印顺序与声明顺序相同,这就意味着在类中可以构建多个init方法,且执行顺序与声明顺序一致。

二级构造器

当类的构造方法有多个重载时,可以使用constructor来构建该重载方法,kotlin中成为次级构造器或二级构造器,需要注意的是,该构造器需要直接或间接调用主构造器

  class A(var name:String, var age:Int ){

    constructor ( name:String):this(name,18){

    }
}

java字节码

public final class A {
   @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 A(@NotNull String name, int age) {
      Intrinsics.checkParameterIsNotNull(name, "name");
      super();
      this.name = name;
      this.age = age;
   }

   public A(@NotNull String name) {
      Intrinsics.checkParameterIsNotNull(name, "name");
      this(name, 18);
   }
}

可以看到二级构造调用了主构造器。那么如果构造器调用类中方法需要注意什么呢?
先看一下这个例子

  class A(var name:String, var age:Int ){


    init {
      foo()
    }

    fun foo(){
        print(num)
    }
    var num=10;

}

java字节码

public final class A {
   private int num;
   @NotNull
   private String name;
   private int age;

   public final void foo() {
      int var1 = this.num;
      System.out.print(var1);
   }

   public final int getNum() {
      return this.num;
   }

   public final void setNum(int var1) {
      this.num = var1;
   }

   @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 A(@NotNull String name, int age) {
      Intrinsics.checkParameterIsNotNull(name, "name");
      super();
      this.name = name;
      this.age = age;
      this.foo();
      this.num = 10;
   }
}

从字节码中可以看出当调用foo方法时num成员变量还没有赋值,执行该方法会打印0,也就是说在执行init代码块时代码块中的数据都应当在调用之前进行赋值。

11-01 11:18:40.837 13672-13672/? I/System.out: 0

那么二级构造器有这种情况吗?
代码

  class A(var name:String, var age:Int ){


     constructor(name:String):this(name,18){
       foo();
     }

     fun foo(){
       println(num);
     }

     var num=10;

}

测试结果

11-01 11:25:04.038 14453-14453/? I/System.out: 10

通过测试未发现二级构造器会出现这种情况.

成员变量的声明

类中成员变量的声明可以这样操作

 open class A(var name:String, var age:Int ){

   var num:String="成员变量";

}

这样就声明了一个成员变量,也可以用可见性修饰符来修饰该成员变量。
那么如何使用该成员变量呢?其实与java差不多,可以通过getxxx和setXXX来获取和设置数据

open class A(var name:String, var age:Int ){

   var num:String="成员变量"
       //创建setter方法
    set(value) {
        field=value;
    }
       //c创建getter方法
    get() {
        return field;
    }

}


   var a=A("zhangsan",18);
        //调用set方法
        a.name="张三"
        //这里调用的是get方法
        println(a.age);
        println(a.name);

测试结果:

11-01 11:49:00.693 15596-15596/com.zhqy.javademo I/System.out: 18
11-01 11:49:00.693 15596-15596/com.zhqy.javademo I/System.out: 张三

需要注意的是这里的a.name=“张三”在底层实现调用的A中的setName(String name)来注入数据,a.name在底层使用的是getName()来获取数据。也就是说A(this).xxx实际调用的xxx的get或set方法

类的继承

如果一个类想要继承父类可以这样操作:

open class A(var name:String, var age:Int ){

    init {
        println("A的构造方法");
    }

    open fun foo(){
        println("调用 A中的foo 方法");
    }

}

class B(var name1:String,var age1:Int ):A(name1,age1 ){

    init {
        println("B 的构造方法");
    }

    override fun foo() {
        super.foo()
        println("调用 B中的方法");
    }

}

测试结果

11-01 11:34:50.445 14939-14939/com.zhqy.javademo I/System.out: A的构造方法
11-01 11:34:50.445 14939-14939/com.zhqy.javademo I/System.out: B 的构造方法
11-01 11:34:50.446 14939-14939/com.zhqy.javademo I/System.out: 调用 A中的foo 方法
11-01 11:34:50.446 14939-14939/com.zhqy.javademo I/System.out: 调用 B中的方法

如果子类想要继承父类则需要使用:来声明继承的父类,且父类需要声明关键字open (类默认被public final 修饰,无法被继承或修改),当父类有主构造器时子类需要调用父类的主构造器,父类中的方法需要被关键字open修饰才能被子类重写,并通过super.xxx()来调用父类方法

如果子类中的内部类想要调用父类中的方法该如何操作呢?

  open class A(var name:String, var age:Int ){

    fun foo(){
       println("A 中的foo方法")
   }

}

class B(var name1:String ,var age1:Int):A(name1,age1){

    inner class C(){
        fun foo1(){
            super@B.foo();
        }

    }
}


 var a=B("zhangsan",18);
         //调用A中的foo方法
        a.C().foo1()

代码中B首先继承自A,B中有一个用inner关键字修饰的内部类C,如果C想要调用A中的方法需要使用kotlin的一个语法: super@XXX.xxx();即调用XXX的父类的xxx方法。测试结果如下

11-01 11:59:31.298 16329-16329/com.zhqy.javademo I/System.out: A 中的foo方法

以上就是Kotlin中class的相关基础内容。

相关文章

  • Kotlin基础(3)-类

    前言 本文主要介绍Kotlin中类的创建以及使用 定义类 kotlin中定义类的方式如下: class 声明其是一...

  • 从零开始学Kotlin-类的继承(6)

    从零开始学Kotlin基础篇系列文章 Kotlin中的超类Any Kotlin 中所有类都继承超类 Any 类 A...

  • Kotlin学习之基础数据类型

    Kotlin学习之基础数据类型 @(Kotlin学习) Kotlin的基础数据类型包括数字类型、字符类型、字符串类...

  • Kotlin基础(类)

    适合有java基础的,获取kotlin基础知识/语法等,Kotlin精讲-黑马程序员(原创)的学习笔记。 类 Ko...

  • kotlin基础-类

    一、类组成 1.主构造函数 参数类型写法的三种情况: 2.次构造函数 次构造函数需要委托给主构造函数(直接委托或者...

  • Kotlin修仙之旅:函数,Lambda表达式,常量,变量

    上一篇文章主要总结了一些Kotlin的基础知识,包括类,对象,数组,区间等(Kotlin基础知识(二)类,对象,数...

  • kotlin基础

    kotlin基础 这次的内容主要是kotlin的基本要素:变量、函数、类。同时学习kotlin的控制语句,if、w...

  • Kotlin基础知识总结 函数二

    在上一篇Kotlin基础的介绍之后,我们继续看看kotlin在函数定义,以及Kotlin类的简单实现。 Kotli...

  • Kotlin学习笔记三 (类相关语法)

    Kotlin类的基础知识 访问修饰符 internal是Kotlin特有的 伴生对象 companion obj...

  • Kotlin第三章小结

    Kotlin没有定义自己的集合类,而是在Java集合类的基础上提供了更丰富的api Kotlin可以给函数参数定义...

网友评论

    本文标题:Kotlin基础(3)-类

    本文链接:https://www.haomeiwen.com/subject/euhfbctx.html