为什么重写 protected 修饰符后无法访问 public 方法?

问题描述 投票:0回答:2

我有一个关于访问修饰符覆盖的问题。

首先我们看一下下面的代码。

fun main() {
    val b: AAA = BBB()

    b.testA()
}

open class AAA() {
    fun testA() {
        println("This is testA()")
    }
}

open class BBB() : AAA()

结果:

This is testA()

这段代码没问题,

b
已经打印了
testA()
类的
AAA.

我们看下面的代码。

fun main() {
    val b: AAA = BBB()

    b.testA()
}

open class AAA() {
    open fun testA() {
        println("This is testA()")
    }
}

class BBB() : AAA() {
    override fun testA() {
        println("This is overrided testA() ")
    }
}

结果:

This is overridden testA()

这段代码也没有问题。

因为

testA()
已被覆盖,所以调用了
testA()
类的
BBB

现在,这是我要问的代码。

fun main() {
    val b: AAA = BBB()

    b.testA()
}

open class AAA() {
    protected open fun testA() {
        println("This is testA()")
    }
}

class BBB() : AAA() {
    public override fun testA() {
        println("This is overridden testA()")
    }
}

这段代码不会被执行。 IDE 抱怨

Cannot access 'testA': it is protected in 'AAA'

虽然

testA()
AAA
protected
,但它在
public
中被重写为
BBB
,所以我认为自然会像第二个代码一样调用
testA()
的重写
BBB

有什么问题吗? 我错过了什么吗? 我误解了继承和访问修饰符的哪一部分?

kotlin overriding access-modifiers
2个回答
0
投票

虽然 AAA 的 testA() 是受保护的,但它在 BBB 中被重写为 public,所以我认为自然会像第二个代码一样调用 BBB 的重写 testA()。

误解是关于何时事情发生。

在运行时,方法调用将动态分派到

b
指向的实例的实际类型。这就是为什么当你实际运行代码时,会使用 BBB 中方法的
implementation
(因为
b
实际上指向
BBB
的实例)。这就是覆盖的工作原理。

然而,在编译时,重要的是用于调用方法

b
的引用变量
testA()
的类型。由于
b
的类型被显式标记为
AAA
,编译器会根据该类型分析您的代码,并且该方法将被解析为
AAA.testA()
以便进行编译。可见性也将基于此进行检查。如果您尝试导航到 IDE 中的函数定义,您实际上可以看到这一点(它会引导您到
AAA
中的定义,而不是
BBB
中的定义)。

简单来说,您可以想象编译器将

b
视为
AAA
,而不对代码运行时它将指向的实际值进行任何假设。

如果您希望编译最后一个代码片段,则必须声明

b
类型为
BBB
(或删除显式类型并让编译器自动将类型推断为
BBB
)。

fun main() {
    val b: BBB = BBB() // or simply val b = BBB()

    b.testA()
}

0
投票

明确地说:

b
AAA
类型,因此不允许访问
b.testA()
,因为它受到保护。

无论

b
对象实际上是什么,您只能使用
AAA
定义的成员。毕竟,
b
也可能是其他一些
AAA
实例,但 not 具有可访问的
testA()
功能。

如果你知道

b
实际上不仅是
AAA
而且还是
BBB
,你可以像这样投射它:

val reallyB: BBB = b as BBB

虽然它在底层是同一个对象,但 varialbe

reallyB
现在是
BBB
类型,因此您可以访问它的任何成员。
testA
现已公开,因此有效:

reallyB.testA()
© www.soinside.com 2019 - 2024. All rights reserved.