美文网首页
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