kotlin编译器插件noarg和allopen的使用

943 阅读9分钟

介绍

kotlin中的数据类,也就是data,他的角色充当我们的JavaBean,但是data修饰的class,有一个问题就是,无法实现一个空的构造参数。

package com.qianfan.forum.entity.live

data class People(var name:String,var age:Int,var sex:Int)

查看字节码可以发现该数据类确实是没有无参构造方法,而且类是final的不可被继承:

package com.qianfan.forum.entity.live;

import kotlin.Metadata;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

@Metadata(
   mv = {1, 1, 18},
   bv = {1, 0, 3},
   k = 1,
   d1 = {"\u0000 \n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0000\n\u0002\u0010\u000e\n\u0000\n\u0002\u0010\b\n\u0002\b\u0011\n\u0002\u0010\u000b\n\u0002\b\u0004\b\u0086\b\u0018\u00002\u00020\u0001B\u001d\u0012\u0006\u0010\u0002\u001a\u00020\u0003\u0012\u0006\u0010\u0004\u001a\u00020\u0005\u0012\u0006\u0010\u0006\u001a\u00020\u0005¢\u0006\u0002\u0010\u0007J\t\u0010\u0012\u001a\u00020\u0003HÆ\u0003J\t\u0010\u0013\u001a\u00020\u0005HÆ\u0003J\t\u0010\u0014\u001a\u00020\u0005HÆ\u0003J'\u0010\u0015\u001a\u00020\u00002\b\b\u0002\u0010\u0002\u001a\u00020\u00032\b\b\u0002\u0010\u0004\u001a\u00020\u00052\b\b\u0002\u0010\u0006\u001a\u00020\u0005HÆ\u0001J\u0013\u0010\u0016\u001a\u00020\u00172\b\u0010\u0018\u001a\u0004\u0018\u00010\u0001HÖ\u0003J\t\u0010\u0019\u001a\u00020\u0005HÖ\u0001J\t\u0010\u001a\u001a\u00020\u0003HÖ\u0001R\u001a\u0010\u0004\u001a\u00020\u0005X\u0086\u000e¢\u0006\u000e\n\u0000\u001a\u0004\b\b\u0010\t\"\u0004\b\n\u0010\u000bR\u001a\u0010\u0002\u001a\u00020\u0003X\u0086\u000e¢\u0006\u000e\n\u0000\u001a\u0004\b\f\u0010\r\"\u0004\b\u000e\u0010\u000fR\u001a\u0010\u0006\u001a\u00020\u0005X\u0086\u000e¢\u0006\u000e\n\u0000\u001a\u0004\b\u0010\u0010\t\"\u0004\b\u0011\u0010\u000b¨\u0006\u001b"},
   d2 = {"Lcom/qianfan/forum/entity/live/People;", "", "name", "", "age", "", "sex", "(Ljava/lang/String;II)V", "getAge", "()I", "setAge", "(I)V", "getName", "()Ljava/lang/String;", "setName", "(Ljava/lang/String;)V", "getSex", "setSex", "component1", "component2", "component3", "copy", "equals", "", "other", "hashCode", "toString", "app_aaqianfanyidongDebug"}
)
public final class People {
   @NotNull
   private String name;
   private int age;
   private int sex;

   @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 final int getSex() {
      return this.sex;
   }

   public final void setSex(int var1) {
      this.sex = var1;
   }

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

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

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

   public final int component3() {
      return this.sex;
   }

   @NotNull
   public final People copy(@NotNull String name, int age, int sex) {
      Intrinsics.checkParameterIsNotNull(name, "name");
      return new People(name, age, sex);
   }

   // $FF: synthetic method
   public static People copy$default(People var0, String var1, int var2, int var3, int var4, Object var5) {
      if ((var4 & 1) != 0) {
         var1 = var0.name;
      }

      if ((var4 & 2) != 0) {
         var2 = var0.age;
      }

      if ((var4 & 4) != 0) {
         var3 = var0.sex;
      }

      return var0.copy(var1, var2, var3);
   }

   @NotNull
   public String toString() {
      return "People(name=" + this.name + ", age=" + this.age + ", sex=" + this.sex + ")";
   }

   public int hashCode() {
      String var10000 = this.name;
      return ((var10000 != null ? var10000.hashCode() : 0) * 31 + this.age) * 31 + this.sex;
   }

   public boolean equals(@Nullable Object var1) {
      if (this != var1) {
         if (var1 instanceof People) {
            People var2 = (People)var1;
            if (Intrinsics.areEqual(this.name, var2.name) && this.age == var2.age && this.sex == var2.sex) {
               return true;
            }
         }

         return false;
      } else {
         return true;
      }
   }
}

使用时只能传参:

People people=new People("lei",23,1);

但是Android的第三方库需要通过反射来加载一些class,这就要求class必需有一个无参的构造函数,而Kotlin的data class默认没有无参构造函数,并且data class默认为final类型,不可以被继承,这造成了第三方库使用的诸多不便。好在Kotlin官方为我们提供了两个插件,可以为我们解决以上两个问题。

noarg和allopen插件

无参编译器插件NoArg插件的作用是:为指定的类在编译时添加一个无参的构造。

全开放编译器插件allopen的作用是:使用指定的注解标注类而其成员无需显式使用 open 关键字打开。

集成noarg和allopen插件

1.在工程的build.gradle文件中添加依赖:

即:

classpath "org.jetbrains.kotlin:kotlin-noarg:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-allopen:$kotlin_version"
2.在app下的build.gradle文件中应用插件:

即:

apply plugin: "kotlin-noarg"
apply plugin: "kotlin-allopen"
3.创建注解类

ps:到此先sync一下,不然第4部写完再sync,4步骤的代码会编译报错

4.在app下的build.gradle文件中添加注解列表:

即:

noArg {
    annotation("com.qianfan.forum.NoArg")
    //即标有com.qianfan.forum.NoArg注解的类编译器会为其生成一个无参构造方法。
}
allOpen {
    annotation("com.qianfan.forum.NoArg")
    //即标有com.qianfan.forum.NoArg注解的类本身及其所有成员会变为开放。
}

另外,allOpen也适用于元注解

比如:

annotation class Annotation
allOpen {
    annotation("com.my.Annotation")
    //即Annotation就是一个全开放注解
}
@com.my.Annotation
annotation class MyFrameworkAnnotation

MyFrameworkAnnotation 已由全开放元注解 com.my.Annotation 标注,所以它也成了一个全开放注解。

@MyFrameworkAnnotation
class MyClass // 将会全开放

使用插件

1.对数据类注解

接下来我们就可以对数据类进行注解了:

package com.qianfan.forum.entity.live

@NoArg
data class People(var name:String,var age:Int,var sex:Int)

然后再看字节码发现就有无参构造方法而且类去掉了final:

package com.qianfan.forum.entity.live;

import kotlin.Metadata;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

@NoArg
@Metadata(
   mv = {1, 1, 18},
   bv = {1, 0, 3},
   k = 1,
   d1 = {"\u0000 \n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0000\n\u0002\u0010\u000e\n\u0000\n\u0002\u0010\b\n\u0002\b\u0011\n\u0002\u0010\u000b\n\u0002\b\u0004\b\u0097\b\u0018\u00002\u00020\u0001B\u001d\u0012\u0006\u0010\u0002\u001a\u00020\u0003\u0012\u0006\u0010\u0004\u001a\u00020\u0005\u0012\u0006\u0010\u0006\u001a\u00020\u0005¢\u0006\u0002\u0010\u0007J\t\u0010\u0012\u001a\u00020\u0003HÆ\u0003J\t\u0010\u0013\u001a\u00020\u0005HÆ\u0003J\t\u0010\u0014\u001a\u00020\u0005HÆ\u0003J'\u0010\u0015\u001a\u00020\u00002\b\b\u0002\u0010\u0002\u001a\u00020\u00032\b\b\u0002\u0010\u0004\u001a\u00020\u00052\b\b\u0002\u0010\u0006\u001a\u00020\u0005HÆ\u0001J\u0013\u0010\u0016\u001a\u00020\u00172\b\u0010\u0018\u001a\u0004\u0018\u00010\u0001HÖ\u0003J\t\u0010\u0019\u001a\u00020\u0005HÖ\u0001J\t\u0010\u001a\u001a\u00020\u0003HÖ\u0001R\u001a\u0010\u0004\u001a\u00020\u0005X\u0096\u000e¢\u0006\u000e\n\u0000\u001a\u0004\b\b\u0010\t\"\u0004\b\n\u0010\u000bR\u001a\u0010\u0002\u001a\u00020\u0003X\u0096\u000e¢\u0006\u000e\n\u0000\u001a\u0004\b\f\u0010\r\"\u0004\b\u000e\u0010\u000fR\u001a\u0010\u0006\u001a\u00020\u0005X\u0096\u000e¢\u0006\u000e\n\u0000\u001a\u0004\b\u0010\u0010\t\"\u0004\b\u0011\u0010\u000b¨\u0006\u001b"},
   d2 = {"Lcom/qianfan/forum/entity/live/People;", "", "name", "", "age", "", "sex", "(Ljava/lang/String;II)V", "getAge", "()I", "setAge", "(I)V", "getName", "()Ljava/lang/String;", "setName", "(Ljava/lang/String;)V", "getSex", "setSex", "component1", "component2", "component3", "copy", "equals", "", "other", "hashCode", "toString", "app_aaqianfanyidongDebug"}
)
public class People {
   @NotNull
   private String name;
   private int age;
   private int sex;

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

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

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

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

   public int getSex() {
      return this.sex;
   }

   public void setSex(int var1) {
      this.sex = var1;
   }

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

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

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

   public final int component3() {
      return this.getSex();
   }

   @NotNull
   public final People copy(@NotNull String name, int age, int sex) {
      Intrinsics.checkParameterIsNotNull(name, "name");
      return new People(name, age, sex);
   }

   // $FF: synthetic method
   public static People copy$default(People var0, String var1, int var2, int var3, int var4, Object var5) {
      if (var5 != null) {
         throw new UnsupportedOperationException("Super calls with default arguments not supported in this target, function: copy");
      } else {
         if ((var4 & 1) != 0) {
            var1 = var0.getName();
         }

         if ((var4 & 2) != 0) {
            var2 = var0.getAge();
         }

         if ((var4 & 4) != 0) {
            var3 = var0.getSex();
         }

         return var0.copy(var1, var2, var3);
      }
   }

   @NotNull
   public String toString() {
      return "People(name=" + this.getName() + ", age=" + this.getAge() + ", sex=" + this.getSex() + ")";
   }

   public int hashCode() {
      String var10000 = this.getName();
      return ((var10000 != null ? var10000.hashCode() : 0) * 31 + this.getAge()) * 31 + this.getSex();
   }

   public boolean equals(@Nullable Object var1) {
      if (this != var1) {
         if (var1 instanceof People) {
            People var2 = (People)var1;
            if (Intrinsics.areEqual(this.getName(), var2.getName()) && this.getAge() == var2.getAge() && this.getSex() == var2.getSex()) {
               return true;
            }
         }

         return false;
      } else {
         return true;
      }
   }

   public People() {
   }
}
2.调用

这个生成的构造函数是合成的,因此不能从Kotlin中直接调用(java却可以),但可以使用反射调用。

internal object Test1 {
    @JvmStatic
    fun main(args: Array<String>) {
        var people1=People("lei",23,1)
        var people2=People::class.java.newInstance()//反射获取People对象的实例
    }
}

java:

People people1=new People("lei",23,1);
People people2=new People();