Kotlin开胃的几个小技巧,陪你到老(二)

999 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第23天,点击查看活动详情

本篇文章介绍两个kotlin中经常使用到的小技巧:抽象属性的两个实现姿势、kotlin接口默认实现的方法java不能直接用

历史文章

你可能需要了解下的Android开发技巧(一)

你可能需要了解下的Android开发技巧(二)

你可能需要了解下的Android开发技巧(三)

抽象属性的两个实现姿势

现在有这样的代码,父类ParentJK,子类BigJKSmallJK

abstract class ParentJK {
    abstract val content: String
}

class SmallJK: ParentJK() {
    override val content: String
        get() = " i am small jk"
}

class BigJK: ParentJK() {
    override val content: String = " i am small jk"
}

子类对于抽象属性content实现方式不同,一个直接赋值,一个重写了get访问器,这两个有什么区别呢,我们看下反编译后的java代码:

ParentJK父类:

public abstract class ParentJK {
   @NotNull
   public abstract String getContent();
}

就是提供了一个getContent()抽象方法供子类重写。

SmallJK方式:

public final class SmallJK extends ParentJK {
   @NotNull
   public String getContent() {
      return " i am small jk";
   }
}

这种方式只是重写了方法getContent(),并没有额外定义其他的属性,没有带来其他开销。

BigJK方式:

public final class BigJK extends ParentJK {
   @NotNull
   private final String content = " i am small jk";

   @NotNull
   public String getContent() {
      return this.content;
   }
}

这个方式除了重写了方法getContent(),还额外定义了一个属性content

经过上面对比我们可以发现,BigJK重写的父类的抽象属性content,和SmallJK比较起来,会额外定义一个content字段带来开销。

所以,我们要根据不同的业务场景选择不同的重写方式:

当重写的属性返回的对象只需要初始化一次,下次获取相同对象时,我们可以选择BigJK方式,其他情况下就可以考虑SmallJK方式,

kotlin接口默认实现的方法为啥java不能使用?

大家都知道,使用kotlin定义接口时,可以给接口方法默认实现,这样子类就可以选择性重写接口方法了:

interface JKWonderful {
    
    fun look() {
        println("JKWonderful: look")
    }
}

这样子类就不用额外重写look()方法了:

image.png

上面这样写不会报错,我们看下在java中是不是也可以这样写:

image.png

可以看到直接报错了,编译器提醒我们要重写look()方法。想要知道原因,我们就得把JKWonderful接口反编译的java代码拿来仔细瞧瞧:

public interface JKWonderful {
   void look();

   public static final class DefaultImpls {
      public static void look(@NotNull JKWonderful $this) {
         String var1 = "JKWonderful: look";
         System.out.println(var1);
      }
   }
}

可以看到并不是JKWonderful接口真正的重写了look()(这在java中也不可能,除非加个default关键字),所以实现这个接口却不是重写方法在java中肯定报错。

那为啥kotlin不重写接口方法不会报错呢,继续看下JKThinLeg这个子类:

public final class JKThinLeg implements JKWonderful {
   public void look() {
      JKWonderful.DefaultImpls.look(this);
   }
}

kotlin编译器已经帮我们处理好了,在JKWonderful的子类JKThinLeg中自动帮助我们重写了方法look(),并默认调用了DefaultImpls.look()的代码逻辑。

如果调用给这个接口方法look()添加一个@JvmSynthetic注解,在java中就不会报错了,也不会提醒实现这个方法,因为这个注解对于实现了这个接口的java类,相当于抹除了这个方法,自然就正常了。