Kotlin 父类中受保护的内联方法可以';无法访问其他受保护的方法

Kotlin 父类中受保护的内联方法可以';无法访问其他受保护的方法,kotlin,inline,access-modifiers,Kotlin,Inline,Access Modifiers,对于以下示例,我在获取非法访问错误时遇到问题: 我在一个名为archgradle模块中声明了一个基类 abstract class BaseClass { protected abstract val value: Int fun run() { Log.d("Printme", "value $value") } protected inline fun getMyValue(): Lazy<Int> = lazy {

对于以下示例,我在获取非法访问错误时遇到问题:

我在一个名为
arch
gradle模块中声明了一个基类

abstract class BaseClass {
    protected abstract val value: Int

    fun run() {
        Log.d("Printme", "value $value")
    }

    protected inline fun getMyValue(): Lazy<Int> = lazy {
        getAnEight()
    }

    protected fun getAnEight() = 8
}
值得一提的是,我正在使用androidstudio创建一个Kotlin项目,但是这些类都是简单的Kotlin对象,没有任何特定于Android的引用。当然,这两个模块也有不同的包

现在,通过我的主要输入方法,我正在执行以下操作(在
app
模块内)

我正在调用基类中声明的
run()
方法,该方法正在访问
value
属性,该属性反过来调用
getAnEight()
方法。由于所有方法都受到保护,我认为没有理由一个子类不能调用所有这些方法。即使其中一个方法被标记为
inline
,并且此调用被方法内容替换,它仍然可以调用
getAnEight()

相反,我收到的是
IllegalAccessError
BaseClass.getAnEight()对类ChildClass$$special$$inlined$getMeValue$1不可访问。当我删除
inline
修饰符时,或者如果我将
BaseClass
ChildClass
放在同一个包中,这个问题就会消失

这是Kotlin编译器中的错误吗?或者有人可以向我解释这种行为,如果它按预期的方式工作的话?提前谢谢

当内联函数是公共函数或受保护函数且不是 私有或内部声明,它被视为模块的公共 应用程序编程接口。它可以在其他模块中调用,并在调用时内联 网站也是如此

这带来了由更改引起的二进制不兼容的某些风险 在模块中声明内联函数,以防调用 更改后不会重新编译模块

以消除由用户引入此类不兼容的风险 更改非公共API的一个模块,公共API内联函数 不允许使用非公共API声明,即私有和 内部声明及其组成部分,在其机构中

内部声明可以用@PublishedApi注释,它 允许在公共API内联函数中使用它。当一个内部内联 函数被标记为@PublishedApi,它的主体也被检查,就好像它 这些都是公开的

编辑:我做了一些字节码研究。问题是受保护的getMyValue()函数被内联到公共构造函数中。在反编译字节码中,ChildClass公共构造函数有以下行:

Lazy var4 = LazyKt.lazy((Function0)(new ChildClass$$special$$inlined$getMyValue$1(this)));
如您所见,它创建了类
ChildClass$$special$$inlined$getMyValue$1
的实例。让我们看看它的声明:

public final class ChildClass$$special$$inlined$getMyValue$1 extends Lambda implements Function0 {

    final BaseClass this$0;

    public ChildClass$$special$$inlined$getMyValue$1(BaseClass var1) {
        super(0);
        this.this$0 = var1;
    }

    public Object invoke() {
        return this.invoke();
    }

    public final int invoke() {
        return this.this$0.getAnEight(); // Here lies the problem
    }
}

创建ChildClass实例时,其构造函数仅创建一个
ChildClass$$special$$inlined$getMyValue$1
实例,该实例不会引发任何错误。但当您调用run()时,将调用上面类的方法。此方法是公共的,其类是公共的,构造函数是公共的,但getAnEight方法受保护。这就是我们得到这个错误的原因。

我已经研究了文档的这一部分,但没有正确理解它。它说:公共API内联函数(如此标记为public或protected)不能使用非公共API声明(如此私有和内部)。但根据这个定义,我的受保护(如此公开的API)函数正在访问另一个受保护(如此公开的API)函数。所以我认为我没有做任何被禁止的事情。通过一些字节码研究扩展了我的答案,也许这会让问题变得更清楚。感谢扩展的研究。当然,当我们看到这一点时,它是有意义的。所以现在我们必须面对一个基本问题——这是不是Kotlin编译器中的一个bug?显然出现了一个错误,因为Kotlin代码是这样翻译成Java字节码的。问题是-也许这是错误的,它应该以一种允许我尝试做的事情的方式进行编译?好吧,这可能是一个bug,但在您的情况下,您并不真正需要内联修饰符。好吧,这是一个bug。关于此问题已经存在一些问题:
Lazy var4 = LazyKt.lazy((Function0)(new ChildClass$$special$$inlined$getMyValue$1(this)));
public final class ChildClass$$special$$inlined$getMyValue$1 extends Lambda implements Function0 {

    final BaseClass this$0;

    public ChildClass$$special$$inlined$getMyValue$1(BaseClass var1) {
        super(0);
        this.this$0 = var1;
    }

    public Object invoke() {
        return this.invoke();
    }

    public final int invoke() {
        return this.this$0.getAnEight(); // Here lies the problem
    }
}