为什么这段Kotlin代码无法访问抽象类的自有成员?
问题原因解答
核心本质:静态类型校验规则
你遇到的差异和抽象类本身无关,核心是Kotlin作为静态类型语言的编译校验规则:编译器只会按照变量的声明类型判断可以访问的成员,不会默认采用运行时的实际实例类型。
你描述的「可以访问抽象类所有被重写的成员,但无法访问它的自有成员」恰好对应这个规则:
- 被重写的
count、peek()等成员,本质上都是Heap或Collection父接口中已经提前声明过的,所以就算变量声明为父接口类型也可以正常访问 elements是AbstractHeap自己新增的、没有在父接口中声明的自有成员,自然无法通过父接口类型访问
两段代码的具体差异
两段代码的核心区别是工厂方法的返回值声明类型不同:
- 堆实现的
create方法声明返回值为Heap<T>
fun <T : Comparable<T>> create(elements: ArrayList<T>): Heap<T> { ... }
此时你拿到的test变量的声明类型是Heap接口,编译器只会允许你访问Heap接口定义的三个成员(count、isEmpty、peek()),自然找不到elements属性。
- 测试代码的
create方法声明返回值为Test1
fun create(): Test1 = a
Test1继承了抽象类Test,i和test()都是Test类本身已经定义的成员,所以可以正常访问。如果你把这个方法的返回值改成Test,依然可以正常访问这两个成员,符合上述规则。
解决方案
可以根据你的业务需求选择任意一种方案:
- 修改
create方法的返回类型为ComparableHeapImpl<T>,让编译器识别到实际子类类型 - 如果
elements需要对外暴露,将elements的声明添加到Heap接口中 - 调用时手动做类型强转:
val a = (test as AbstractHeap<Int>).elements[0]
内容的提问来源于stack exchange,提问作者ntos
相关产品推荐
相关产品推荐

