Android抽象Fragment子类newInstance()实现疑问:无需泛型返回子类实例?
解决方案:用Reified泛型+Inline函数实现无泛型传入的类型安全实例化
当然可以做到!借助Kotlin的reified泛型和inline函数,我们可以在父类MyClass的伴生对象中定义一个通用的newInstance()方法,既不用手动传入泛型类型,还能确保返回对应子类的正确类型。
第一步:实现父类的通用newInstance()方法
在MyClass的伴生对象中定义一个inline reified函数,它可以直接获取泛型的实际类型,从而创建对应子类的实例:
abstract class MyClass : Fragment() { companion object { // 用reified让泛型类型在运行时可见,inline是reified的必要条件 inline fun <reified T : MyClass> newInstance(): T { // 反射创建实例,若子类有带参数的构造函数,可调整这里的反射逻辑 return try { T::class.java.getConstructor().newInstance() } catch (e: Exception) { throw RuntimeException("Failed to create instance of ${T::class.simpleName}", e) } } } }
第二步:无泛型传入的调用方式
你不需要手动传入泛型类型,编译器可以通过类型推断自动识别需要的子类类型:
方式1:通过变量类型推断
class SubClass1 : MyClass() class SubClass2 : MyClass() // 直接声明变量类型,编译器会自动推断T为SubClass1 val instance1: SubClass1 = MyClass.newInstance() // 同理,这里推断为SubClass2 val instance2: SubClass2 = MyClass.newInstance()
方式2:让子类拥有自己的newInstance()(无重复代码)
如果你希望子类可以像SubClass.newInstance()这样直接调用,而不是通过MyClass,可以在子类的伴生对象中写一行极简的委托代码,不用重复实例化逻辑:
class SubClass : MyClass() { companion object { // 直接调用父类的泛型方法,指定当前子类类型 fun newInstance(): SubClass = MyClass.newInstance() } } // 调用时完全不用管泛型,直接拿到SubClass类型的实例 val subInstance = SubClass.newInstance()
补充:带参数的newInstance()扩展
如果你的Fragment需要传递参数,只需要在方法里添加Bundle逻辑即可,同样保持类型安全:
inline fun <reified T : MyClass> newInstance(param: String): T { val fragment = T::class.java.getConstructor().newInstance() val args = Bundle().apply { putString("KEY_PARAM", param) } fragment.arguments = args return fragment } // 调用时依然支持类型推断 val instanceWithParam: SubClass = MyClass.newInstance("test data")
这样一来,既满足了所有子类共享父类的newInstance()实现,又能保证返回类型的正确性,还不用手动传入泛型参数~
内容的提问来源于stack exchange,提问作者RedBassett
相关产品推荐
相关产品推荐

