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

在将块从一个类传递到另一个类时,如何访问Kotlin中的私有成员

杨柏
2023-03-14

我有一个名为ClassA的类,我希望它是完全私有的,除了一个可以接收并执行代码块的方法。我希望我传递给这个方法的代码块能够调用ClassA的私有成员。这是我现在所拥有的一个非常简化的表示:

class ClassA() {  
    private fun printFoo(session: SessionInfo){
        System.out.println("Foo")
    }

    fun runBlock(block: ClassA.() -> Unit) {
        this.block()
    }
}

class ClassB(var classA: ClassA) {    
    fun doThing() {
            classA.runBlock { this.printFoo() }
    }
}

上面的代码无法编译,因为printFoo在ClassA中只是私有访问。如果我更改它对公共的访问,则此代码工作正常。有没有办法我可以在我从 B 类传入的块中引用这个 printFoo,而不必公开该方法?

共有1个答案

袁宜
2023-03-14

有两种方法可以解决这个问题:使用反射或代理访问器。

反思几乎可以让你做任何你喜欢的事情。您始终可以使用它强制通过密封:

class HasPrivateMembers(private val foo: String)

fun main() {
    val x = HasPrivateMembers("bar")
//    println(x.foo) // doesn't work due to private specifier
    val foo = x.javaClass.getDeclaredField("foo").run {
        isAccessible = true
        get(x) as String
    }.also {
        println(it)
    }
}

不过我不会采取这种方法。感觉有点笨拙,应该有这种感觉。如果你认可这种方法,你就不会设计一个对你的领域的架构访问。你基本上表明不应该访问你的IELDS,但如果一个人希望直接与它们交互(甚至违反不变量,如果有的话),他们可以自由使用可以做到这一点的工具。

这就引出了第二种方法。

这个想法是创建一个私有内部类,该类将用于委托对它与 ClassA 共享的 API 的调用:

class ClassA {
    private var privateField = "this is private"

    private fun printFoo(){
        println("Foo")
    }

    interface Accessor {
        fun printFoo()
        var privateField: String
    }

    private inner class AccessorImpl : Accessor {
        override fun printFoo() {
            this@ClassA.printFoo()
        }

        override var privateField: String
            get() = this@ClassA.privateField
            set(value) {
                this@ClassA.privateField = value
            }
    }

    fun runBlock(block: Accessor.() -> Unit) {
        AccessorImpl().block()
    }
}

class ClassB(var classA: ClassA) {
    fun doThing() {
        classA.runBlock {
            printFoo()
            privateField = "but I just changed it"
        }
    }
}

这里发生了很多变化,所以让我解释每一个变化,以使片段有意义:

>

  • private var privateField=“this is private”-我添加了一个额外的private字段,以证明上述解决方案也适用于数据字段。

    接口访问器-这是核心思想。我们有一个公共接口,它充当外部世界和委托访问私有字段的私有实现之间的粘合剂。

    私有内部类 AccessorImpl - 这是核心思想的实现。

    > < li>

    它是< code>private,因此没有人能够利用它,并且唯一可以使用它的方法是通过您提供的< code>runBlock()。

    它是一个内部类,因此它的对象包含对适当ClassA实例的引用(因此是this@ClassA部分)。

    它与您的< code>ClassA具有相同的字段,但被设为< code>public。

    它所做的只是将每个操作委托给外部类的对象。

    fun runBlock(block: Accessor.() -

    • AccessorImpl()。block()-我们需要为创建一个Accessor以供调用。我们需要一个能够与 AccessorImpl ,并对其调用block()。请记住,由于AccessorImpl内部类,因此它知道它绑定到了调用了 的对象

    虽然我强烈喜欢第二种解决方案而不是第一种解决方案,但请记住,在正常情况下不应违反密封化。每次您更改 A 类的私有 API 时(那...听起来确实很奇怪,但这就是我们在这里处理的内容),您必须更改 AccessorAccessorImpl 以反映这一点。围绕它没有简单的解决方法,坦率地说,我相信这是一件好事。在处理此类架构时,您应该格外小心。

  •  类似资料:
    • 在Java和Android中,我们可以这样做: 这样,在其他地方,我们就可以做到这一点: //编辑也许我应该说得更清楚些。我的意思是我们如何才能用Kotlin写上面的内容,用Kotlin。

    • 我是一名Java程序员初学者。我试图在类交通中访问类车中的两个列表,这样我就可以执行while循环,循环直到主类中的列表为空 这就是我现在掌握的代码,我试着从普通车上扩展流量,但没有成功,我被卡住了。我该怎么解决这个问题?

    • 问题是: 在本例中,我通过用芒果扩展MainClass得到了结果:mango two。但是在我的项目中,MainClass已经扩展到了另一个类。这就是为什么我要使用一个接口,我将用MainClass实现Mango类的重写方法 好像我可以从芒果类接收数据

    • 问题内容: 我想将一个类变量传递给另一个类,并使其成为该类的类变量。在以下情况下我该怎么做? 问题答案: 很难理解您正在问的问题,但这是一个可能的答案: 使B类成为A的子类: 如果重新声明为,则会出现一种情况,其中存在一个可以称为或的属性。(或在任一或刚刚…甚至作为或地方,并有类型和分别。) 如果您无法在和(或,以及一些包含声明的第三类)之间创建直接或子类型关系,那么您很不走运。他们无法共享声明。

    • 我是selenium初学者,只是想把webDriver传递给另一个类,但没有成功。程序应该打开浏览器(“Google”)并在主类中键入一些单词,在第二个类中应该按下“Google”按钮。 以下是我的主要课程: 这是我想从主驱动程序中使用的类。 当我运行它时,它对我说: 传递:main失败:printOnScreen java.lang.NullPointerException 我做错了什么?谢谢高