为什么我必须将自定义适配器对象强制转换为类?

Why Do I Have to Cast My Custom Adapter Object to a Class?

提问人:Robbie 提问时间:2/9/2023 更新时间:2/10/2023 访问量:54

问:

我正在使用 Kotlin 开发一个简单的 Android 应用程序,目前正在实现 .我的类 , 与我在 .我把它附在我的喜欢中:android.widget.BaseAdapterGridAdapterGridViewactivity_main.xmlMainActivity.kt

val gridView = findViewById<GridView>(R.id.gridView)
gridView.adapter = GridAdapter(applicationContext)

我不明白的是,每当我想调用该适配器的函数之一时,我必须首先将其(对象)转换为,如下所示:GridAdapterGridAdapter

(gridView.adapter as GridAdapter).addImage(imageView)

尽管事实未声明为静态,但这是事实。下面是方法签名:addImage

fun addImage(image: ImageView)

在我看来,这似乎是一个荒谬的陈述,在任何其他情况下都会立即导致编译错误,但 Android Studio linter 却对此发誓。为什么?这是怎么回事?

Android Kotlin GridView 转换 适配器

评论


答:

0赞 Emanuel Moecklin 2/9/2023 #1

GridView的适配器是(继承自 ):ListAdapterAbsListView

ListAdapter mAdapter;

每当你访问时,你都会从编译器的角度得到一个不是你的。由于您知道它始终是运行时的,因此您可以将其强制转换而不会冒 .gridView.adapterListAdapterGridAdapterGridAdapterClassCastException

addImage似乎是一个函数,因此需要强制转换来调用该函数。 根本没有那个功能。GridAdapterListAdapter

与其每次都进行强制转换,不如保留对你的引用并使用该引用呢?喜欢GridAdapter

val adapter = GridAdapter(applicationContext)
gridView.adapter = adapter
adapter.addImage(imageView)
0赞 Tenfour04 2/10/2023 #2

的签名 has it 返回一个泛型,因为您可以将其设置为 的任何子类型,因为 OOP 的 Liskov 替换原理。GridAdapter.adapterAdapterAdapter

它返回给您的实际适配器是 GridAdapter,因为这是您之前传递给它的子类型。但编译器并不知道这一点。编译器无法确定在此特定情况下,返回的 Adapter 是专门的 GridAdapter。适配器可能已在另一个函数中或由另一个线程等更改为其他类型。编译器永远不可能复杂到足以弄清楚这样的事情,因为它无法在每次键入一行代码时都运行应用程序的整个模拟,因此它可以分析和找出所有的可能性。

所以你强制转换它来告诉编译器,它实际上是一个 .请记住,强制转换实际上并未执行任何转换。这只是你对编译器做出的承诺,即你正在使用的变量已经是你声称的类型。AdapterGridAdapter

我不确定你为什么提到这个函数不是静态的。这与选角无关。