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

以下是我的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所以也是不可以被继承的

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350