当前位置: 首页 > 知识库问答 >
问题:

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

督俊雅
2023-03-14

我有一个Java类(外层),它使用内部构建器类(外层。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中,外部类看不到内部类的私有成员。

此代码在init块中运行,其中:

mValue = builder.mValue

我知道我可以对其进行重构,以避免尝试这种访问(更改外部构造函数,使其包含所有成员,为必要的字段等向外部.Builder添加访问器),但我想知道是否有一种惯用的Kotlin方法来实现这种构建器模式(如果可能的话,只需对初始Java类进行最小的修改)。

共有1个答案

华懿轩
2023-03-14

静态编程语言具有命名参数,因此整个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创建外部函数,我们需要声明一个辅助顶级函数,其名称与可用于复制构造函数的类型相同:

@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);
    }
}

静态编程语言的用法:

fun main() {
    val outer = Outer { mValue = 42 }
    outer.printValue(System.out)
}
 类似资料:
  • 我正在装一个应用程序,它工作得很好。但当我使用 在OuterClass中,并通过

  • 问题内容: 我观察到外部类可以访问内部类的私有实例变量。这怎么可能?这是演示相同代码的示例代码: 为什么允许这种行为? 问题答案: 内部类只是一种将真正属于原始外部类的功能完全分开的方法。当你有两个要求时,可以使用它们: 如果是在单独的类中实现的,那么外部类中的某些功能将最为清晰。 即使在单独的类中,该功能也与外部类的工作方式紧密相关。 鉴于这些要求,内部类可以完全访问其外部类。由于它们基本上是外

  • 我认为内部类的成员,即使被声明为私有的,也可以从它的封闭类中访问。但是我遇到了以下代码结构的编译时错误。我的顶级类实现了Iterable接口。Iterator在内部类中实现。当内部类的一个实例通过iterator()方法获得时,我无法使用该实例访问数据栏。 有什么建议吗?

  • 问题内容: 在Java中,内部类可以访问封闭类的私有成员。但是外层可以访问内层的私有成员吗?这与内部类是否静态无关。我认为这是不正确的,但是以下代码似乎可以编译并正常工作。 问题答案: 是的,没关系。从JLS,第6.6.1节中: 否则,如果声明了成员或构造函数,则仅当访问发生在封装成员或构造函数的声明的顶级类(第7.6节)的主体内时,才允许访问。 您甚至可以在另一个嵌套类型Y中引用嵌套类型X的私有

  • 我一直在试图理解java中嵌套类的机制。 考虑以下代码: } 我知道内部类是编译器的一种现象,虚拟机不知道它们。内部类被翻译成带有$分隔外部和内部类名的常规类文件。 为了更详细地理解这种机制,我尝试使用javap-p命令反汇编在java版本1.8中编译的类文件。 我得到了以下结果:OuterClass: 内部类: 在这里我们可以看到编译器通过构造函数将外部类的引用传递给内部类,以便它可以评估外部类

  • 为什么这段代码不起作用 在这段代码工作的时候? 在第一段代码中,当我试图通过内部类“a”的对象引用内部类“a”的实例变量“x”时,我得到一个错误,说我是在静态上下文中使用内部类。在其他方法中执行相同操作时没有错误。