美文网首页
kotlin基础知识—基础语法(二)

kotlin基础知识—基础语法(二)

作者: Peakmain | 来源:发表于2020-06-29 08:37 被阅读0次

    以下是我的kotlin系列文章
    kotlin基础知识—基本语法(一)

    前言

    • 我个人使用的工具是Android Studio

    • 写这篇文章呢,主要是熟悉了解kotlin

    • kotlin教程:http://www.runoob.com/kotlin

    • 不讲基本使用

    • 查看kotlin字节码和转成java

      image image

    • 基本使用
    class A{
    }
    

    转成对应的Java代码

    public final class A {
    }
    

    因此我们可以看到默认kotlin的类是final类,不可被继承,如果想要可被继承我们需要在类的前面加上open

    类的属性

    • 属性的定义和使用
    class A {
        var name: String = "test"
    }
    fun main() {
        val a = A()
        print(a.name)
    }
    

    转成Java代码

    public final class A {
       @NotNull
       private String name = "test";
    
       @NotNull
       public final String getName() {
          return this.name;
       }
    
       public final void setName(@NotNull String var1) {
          Intrinsics.checkParameterIsNotNull(var1, "<set-?>");
          this.name = var1;
       }
    }
       public static final void main() {
          A a = new A();
          String var1 = a.getName();
          boolean var2 = false;
          System.out.print(var1);
       }
    

    所以a.name实际调用的是a.getName方法

    • 构造器
      Koltin 中的类可以有一个 主构造器,以及一个或多个次构造器,主构造器是类头部的一部分,位于类名称之后:
    class Person constructor(firstName: String) {}
    

    如果主构造器没有任何注解,也没有任何可见度修饰符,那么constructor关键字可以省略。

    class Person(firstName: String) {
    }
    

    转成Java代码

    public final class Person {
       public Person(@NotNull String firstName) {
          Intrinsics.checkParameterIsNotNull(firstName, "firstName");
          super();
       }
    }
    

    主构造器中不能包含任何代码,初始化代码可以放在初始化代码段中,初始化代码段使用 init 关键字作为前缀。

    • 次构造函数
      类也可以有二级构造函数,需要加前缀 constructor:
    class Person { 
        constructor(parent: Person) {
            parent.children.add(this) 
        }
    }
    

    如果类有主构造函数,每个次构造函数都要,或直接或间接通过另一个次构造函数代理主构造函数。在同一个类中代理另一个构造函数使用 this 关键字:

    class Person (firstName: String,age:Int) {
        constructor(firstName: String):this(firstName,0){
        }
    }
    

    转成对应Java代码

    public final class Person {
       public Person(@NotNull String firstName, int age) {
          Intrinsics.checkParameterIsNotNull(firstName, "firstName");
          super();
       }
    
       public Person(@NotNull String firstName) {
          Intrinsics.checkParameterIsNotNull(firstName, "firstName");
          this(firstName, 0);
       }
    }
    

    私有的默认构造方法

    class Person private constructor(){
    }
    

    转成对应Java代码

    public final class Person {
       private Person() {
       }
    }
    

    内部类

    • 内部类使用 inner 关键字来表示。
    • 内部类会带有一个对外部类的对象的引用,所以内部类可以访问外部类成员属性和成员函数。
    class Person {
        private val age = "23"
    
        inner class B {
            var b = age
        }
    }
    

    转成对应Java代码

    public final class Person {
       private final String age = "23";
       public final class B {
          @NotNull
          private String b;
          @NotNull
          public final String getB() {
             return this.b;
          }
          public final void setB(@NotNull String var1) {
             Intrinsics.checkParameterIsNotNull(var1, "<set-?>");
             this.b = var1;
          }
    
          public B() {
             this.b = Person.this.age;
          }
       }
    }
    

    第二种获取外部类属性

    class Person {
        private val age = "23"
    
        inner class B {
            fun test(){
                var a = this@Person
                var b=a.age
            }
        }
    
    }
    

    转成对应Java代码

    public final class Person {
       private final String age = "23";
       public final class B {
            public final void test() {
             Person a = Person.this;
             String b = a.age;
          }
       }
    }
    

    两种方式主要区别在于一个是B的函数的内部属性,一个是外部属性

    • 匿名内部类
    class Test {
        var v = "成员属性"
    
        fun setInterFace(test: TestInterFace) {
            test.test()
        }
    }
    /**
     * 定义接口
     */
    interface TestInterFace {
        fun test()
    }
    

    转成Java代码

    public interface TestInterFace {
       void test();
    }
    public final class Test {
       @NotNull
       private String v = "成员属性";
    
       @NotNull
       public final String getV() {
          return this.v;
       }
    
       public final void setV(@NotNull String var1) {
          Intrinsics.checkParameterIsNotNull(var1, "<set-?>");
          this.v = var1;
       }
       public final void setInterFace(@NotNull TestInterFace test) {
          Intrinsics.checkParameterIsNotNull(test, "test");
          test.test();
       }
    }
    

    kotlin继承

    构造函数

    • 子类有主构造函数
      如果子类有主构造函数, 则基类必须在主构造函数中立即初始化。
    open class Person(var name : String, var age : Int){// 基类
    
    }
    class Student(name : String, age : Int, var no : String, var score : Int) : Person(name, age) {
    
    }
    

    转成对应Java代码

    public class Person {
       @NotNull
       private String name;
       private int age;
       //set和get方法省略
       public Person(@NotNull String name, int age) {
          Intrinsics.checkParameterIsNotNull(name, "name");
          super();
          this.name = name;
          this.age = age;
       }
    }
    public final class Student extends Person {
       @NotNull
       private String no;
       private int score;
       //set和get方法省略
       public Student(@NotNull String name, int age, @NotNull String no, int score) {
          Intrinsics.checkParameterIsNotNull(name, "name");
          Intrinsics.checkParameterIsNotNull(no, "no");
          super(name, age);
          this.no = no;
          this.score = score;
       }
    }
    
    • 子类没有主构造函数
      如果子类没有主构造函数,则必须在每一个二级构造函数中用 super 关键字初始化基类,或者在代理另一个构造函数。初始化基类时,可以调用基类的不同构造方法。
    open class Person(context: Context, attrs: AttributeSet?) {
        // 基类
        constructor(context: Context) : this(context, null) {
    
        }
    }
    class Student : Person {
        constructor(ctx: Context) : super(ctx) {
        }
        constructor(ctx: Context, attrs: AttributeSet) : super(ctx, attrs) {
        }
    }
    

    扩展

    • 扩展函数
      扩展函数可以在已有类中添加新的方法,对被扩展的类代码本身不会造成任何影响
    fun MutableList<Int>.swap(index1: Int, index2: Int) {
        val tmp = this[index1]     //  this 对应该列表
        this[index1] = this[index2]
        this[index2] = tmp
    }
    

    转成对应Java代码

       public static final void swap(@NotNull List list, int index1, int index2) {
          Intrinsics.checkParameterIsNotNull(list, "$this$swap");
          int tmp = ((Number)list.get(index1)).intValue();
         list.set(index1, list.get(index2));
          list.set(index2, tmp);
       }
    
    • 扩展一个空对象
    fun Any?.toString(): String {
        if (this == null) return "null"
        // 空检测之后,“this”会自动转换为非空类型,所以下面的 toString()
        // 解析为 Any 类的成员函数
        return toString()
    }
    

    转成对应的Java代码

     public static final String toString(@Nullable Object $this$toString) {
          return $this$toString == null ? "null" : $this$toString.toString();
       }
    

    伴生对象的扩展
    如果一个类定义有一个伴生对象 ,你也可以为伴生对象定义扩展函数和属性。
    伴生对象通过"类名."形式调用伴生对象,伴生对象声明的扩展函数,通过用类名限定符来调用:

    • 伴生对象
      Kotlin 中是没有静态方法的,解决的办法有两种,一种方法就是使用 @JvmStatic 注解去注释它,第二种方法就是使用伴生对象的方式创建
    class MyClass {
        companion object {
            val age=30
        }  // 将被称为 "Companion"
    }
    val MyClass.Companion.no: Int
        get() = 10
    
    fun main() {
        println("no:${MyClass.no}")
    }
    

    转成Java代码

    public final class MyClass {
       private static final int age = 30;
       public static final MyClass.Companion Companion = new MyClass.Companion((DefaultConstructorMarker)null);
    
       public static final class Companion {
          public final int getAge() {
             return MyClass.age;
          }
    
          private Companion() {
          }
    
          // $FF: synthetic method
          public Companion(DefaultConstructorMarker $constructor_marker) {
             this();
          }
       }
    }
    // KotlinKt.java
    package com.peakmain.leetcode;
    
    public final class KotlinKt {
       public static final int getNo(@NotNull MyClass.Companion $this$no) {
          Intrinsics.checkParameterIsNotNull($this$no, "$this$no");
          return 10;
       }
    
       public static final void main() {
          String var0 = "no:" + getNo(MyClass.Companion);
          boolean var1 = false;
          System.out.println(var0);
       }
    
       // $FF: synthetic method
       public static void main(String[] var0) {
          main();
       }
    }
    

    数据类与密闭类

    • 数据类
      Kotlin 可以创建一个只包含数据的类,关键字为 data:
     data class User(val name: String, val age: Int)
    

    转成Java代码

    public final class User {
       @NotNull
       private final String name;
       private final int age;
    
       @NotNull
       public final String getName() {
          return this.name;
       }
    
       public final int getAge() {
          return this.age;
       }
    
       public User(@NotNull String name, int age) {
          Intrinsics.checkParameterIsNotNull(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 User copy(@NotNull String name, int age) {
          Intrinsics.checkParameterIsNotNull(name, "name");
          return new User(name, age);
       }
    
       @NotNull
       public String toString() {
          return "User(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 User) {
                User var2 = (User)var1;
                if (Intrinsics.areEqual(this.name, var2.name) && this.age == var2.age) {
                   return true;
                }
             }
             return false;
          } else {
             return true;
          }
       }
    }
    
    

    我们会发现kotlin默认会帮我们生成hashCode和equalus,而且这个类是final,也就是说这个类是不可被继承 (但是可以实现接口)的,copy实际上就是new一个新的实体类,每一个属性都会有一个component。

    密闭类

    • 密封类用来表示受限的类继承结构:当一个值为有限几种的类型, 而不能有任何其他类型时。在某种意义上,他们是枚举类的扩展:枚举类型的值集合 也是受限的,但每个枚举常量只存在一个实例,而密封类 的一个子类可以有可包含状态的多个实例。
    • 声明一个密封类,使用 sealed 修饰类,密封类可以有子类,但是所有的子类都必须要内嵌在密封类中。
      sealed 不能修饰 interface ,abstract class(会报 warning,但是不会出现编译错误)
    sealed class Expr{
        open class A: Expr() {
    
        }
        class B:Expr(){
        }
    }
    fun exec(expr: Expr)=when(expr){
         is Expr.A->{
    
        }
        is Expr.B->{
            
        }
    }
    

    转成对应Java代码

    public abstract class Expr {
       private Expr() {
       }
    
       // $FF: synthetic method
       public Expr(DefaultConstructorMarker $constructor_marker) {
          this();
       }
    
       public static class A extends Expr {
          public A() {
             super((DefaultConstructorMarker)null);
          }
       }
    
       public static final class B extends Expr {
          public B() {
             super((DefaultConstructorMarker)null);
          }
       }
    }
    

    我们可以从转后的Java可以看到,外部类是无法去继承Expr的,因为构造方法是私有的,但是可以继承A,因为B是final所以也是不可以被继承的

    相关文章

      网友评论

          本文标题:kotlin基础知识—基础语法(二)

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