0

以下示例:

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

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)
    }
}

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

4

2 回答 2

1

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

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(...

编辑:hashmap 注册表的想法,以允许一些可扩展性..

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(...
于 2018-09-13T19:37:47.030 回答
0

我真的没有看到你的问题。请注意,泛型类型信息在运行时被删除(至少对于您显然正在使用的 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>并不能确保您拥有 type 类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")

使用实际上为 no 的类型调用它Vehicle会给你一个ClassCastExceptionat 接口的start-function。

于 2018-09-14T06:35:49.473 回答