繁体   English   中英

从 Java 到 Kotlin 的惯用迁移 class 访问内部 ZA2F2ED4F8EBC2CBB1DC21A29ZDC 私有成员

[英]Idiomatic migration from Java to Kotlin of class that accesses inner class private members

我有一个 Java class ( Outer ),它使用内部构建器 class ( Outer.Builder ),访问私有变量作为构造的一部分,如下所示:

import java.io.PrintStream;

public class Outer {
  private int mValue;

  private Outer(Builder builder) {
    mValue = builder.mValue;
  }

  public void printValue(PrintStream stream) {
    stream.println(mValue);
  }

  public static class Builder {
    private int mValue;

    public Builder setValue(int value) {
      mValue = value;
      return this;
    }

    public Outer build() {
      return new Outer(this);
    }
  }
}

使用如下:

class Main {
  public static void main(String[] args) {
    var builder = new Outer.Builder();
    var outer = builder.setValue(42).build();
    outer.printValue(System.out);
  }
}

我试图利用 Android Studio 将 Java 代码迁移到 Kotlin 的能力,这给了我以下结果:

import java.io.PrintStream

class Outer private constructor(builder: Builder) {
  private val mValue: Int

  fun printValue(stream: PrintStream) {
    stream.println(mValue)
  }

  class Builder {
    private var mValue = 0

    fun setValue(value: Int): Builder {
      mValue = value
      return this
    }

    fun build(): Outer {
      return Outer(this)
    }
  }

  init {
    mValue = builder.mValue
  }
}

但是,编译失败,出现:

Outer.kt:24:22: error: cannot access 'mValue': it is private in 'Builder'
    mValue = builder.mValue
                     ^

因为(如Kotlin 文档所述):

在 Kotlin 中,外部 class 看不到其内部类的私有成员。

这段代码在init块中运行,与:

mValue = builder.mValue

我知道我可以重构它以不尝试此访问(更改Outer构造函数以使其获取所有成员,将访问器添加到Outer.Builder以获取必要的字段等),但我想知道是否存在是一种惯用的 Kotlin 方式来实现这种构建器模式(如果可能,对初始 Java class 进行最小修改)。

Kotlin命名为 arguments ,因此整个 Builder 模式嵌入到语言中:

class Outer(private val mValue: Int = 0) {
    fun printValue(stream: PrintStream) = stream.println(mValue)
}

//Usage:
fun main() {
    val outer = Outer(mValue = 42)
    outer.printValue(System.out)
}

但是,这种方法仅适用于 Kotlin 的使用。 对于 Java 的用法,构造函数应变为私有,并且应声明传统的嵌套生成器:

class Outer private constructor(val mValue: Int) {
    class Builder {
        @set:JvmSynthetic // Hide 'void' setter from Java
        var mValue: Int = 0

        fun setValue(value: Int) = apply { this.mValue = value }

        fun build() = Outer(mValue)
    }

    fun printValue(stream: PrintStream) = stream.println(mValue)
}

为了方便地从 Kotlin 创建Outer ,我们需要声明一个辅助顶级 function,其名称与我们可以用来复制构造函数的类型相同:

@JvmSynthetic // Hide from Java callers who should use Builder.
fun Outer(initializer: Outer.Builder.() -> Unit): Outer {
    return Outer.Builder().apply(initializer).build()
}

来自 Java 的用法:

public class BuilderUsage {
    public static void main(String[] args) {
        Outer outer = new Outer.Builder().setValue(42).build();
        outer.printValue(System.out);
    }
}

Kotlin 的用法:

fun main() {
    val outer = Outer { mValue = 42 }
    outer.printValue(System.out)
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM