如何按名称实例化参数化类型类



以下示例:

我有一项可以"启动"任何车辆的服务

interface VehicleStarterService<T: Vehicle> {
fun <T : Vehicle> start(vehicle: Class<T>): String {
return vehicle.start
}
}

我想通过名称启动一个车辆类型,如"Car",这将需要我创建一个 VehicleStarterService;但是我似乎找不到一种方法来实例化一个由名称实例化的类的接口。

我想做类似的事情(但不能(:

val cls = "Car"
val kClass = Class.forName(cls).kotlin
val service = VehicleStarterService<kClass>()
service.start

我最终不得不执行以下操作(为我需要的每个参数化类型创建一个服务(:

class CarStarterService : VehicleStarterService<Car> {
fun <T> execute() : String {
return start(User::class.java)
}
}

有没有办法以这种方式实例化参数化的类?

目前尚不清楚这是否足以满足您的情况,但也许您可以像这样根据字符串匹配类

val cls = "Car"
val service: VehicleStarterService<out Vehicle>? = when (cls) {
"Car"  -> object : VehicleStarterService<Car> {}
"Boat" -> object : VehicleStarterService<Boat> {}
"Plane" -> object : VehicleStarterService<Plane> {}
else   -> null
}
service?.start(...

编辑:哈希图注册表的想法允许一些可扩展性。

val serviceRegistry = HashMap<String, VehicleStarterService<out Vehicle>>()
.apply {
//default services
this["Car"] = object : VehicleStarterService<Car> {}
this["Boat"] = object: VehicleStarterService<Boat> {}
}
.
.
.
//Adding entry
serviceRegistry["Plane"] = object: VehicleStarterService<Plane> {}
.
.
.
//Fetching entry
val cls = "Car"
val service = serviceRegistry[cls]
service?.start(...

我真的看不出你的问题。请注意,泛型类型信息在运行时被擦除(至少对于您显然正在使用的 JVM 变体(。因此,使用哪种通用类型服务基本上无关紧要。 您也可以只使用VehicleStarterService<Vehicle>,它将启动您的所有车辆。如果出于任何原因你需要调用一个特定的(其他!(函数,你仍然需要检查/强制转换为你的实际类型......因此,我认为尝试获取该通用类型化接口没有任何好处。

话虽如此,仍然有方法可以做到这一点...(再次注意:这并不重要...泛型类型信息在运行时被擦除...

现在对于我的测试,我使用这个输入方法:

fun startAllTheVehicles(vararg vehicleTypes: String) {
startAllTheVehicles(*vehicleTypes.map { Class.forName(it) }
.map { it as Class<out Vehicle> }
.toTypedArray())
}

请注意,it as Class<out Vehicle>并不能确保您具有类型Vehicle的类。它只是确保代码在尝试调用将Class<out Vehicle>声明为参数类型的函数时进行编译。

因此,从那里开始,您可以使用以下方法之一来提供实际的泛型类型。我假设您在启动服务中使用类似newInstance的东西。

  1. 接口上省略泛型类型的示例(这种情况相当容易(:

    interface VehicleStarterService {
    fun <T: Vehicle> start(vehicleType: Class<T>) = vehicleType.newInstance().start
    }
    

    上述入口函数调用的示例方法,使用一个服务启动所有车辆:

    fun <T : Vehicle> startAllTheVehicles(vararg vehicleTypes: Class<out T>) {
    val service = object : VehicleStarterService {}
    vehicleTypes.forEach { service.start(it) }
    }
    
  2. 仍然使用泛型类型的接口(请注意有关out T等的更改(:

    interface VehicleStarterService<T: Vehicle> {
    fun start(vehicleType: Class<out T>) = vehicleType.newInstance().start
    }
    

    入口函数使用一个服务启动所有车辆的示例方法:

    fun <T : Vehicle> startAllTheVehicles(vararg vehicleTypes: Class<out T>) {
    // actually it doesn't really matter which type we use...
    val service = object : VehicleStarterService<Vehicle> {} // you could even use T instead of Vehicle
    vehicleTypes.forEach { service.start(it) }
    }
    

按预期使用以下方法测试两者:

startAllTheVehicles("Car", "Truck")

使用实际上没有Vehicle的类型调用它会使您在接口的start函数中ClassCastException

最新更新