嘿,我刚刚发现了类型转换,但是我不理解其背后的概念吗?你为什么要使用这样的东西。我试图举一个例子来更好地理解它:
interface Fuel {
//Fuel.kt
var usingFuel : Boolean
var typeFuel : String
fun printInfo(){
println("Using this Fuel type: $typeFuel")
}
}
class Airplane(name : String, age : Int, amountFuel: Double) : Vehicle(name, age, amountFuel), Fuel {
//Airplane.kt
override var usingFuel: Boolean = true
override var typeFuel: String = "Kerosin"
override fun printInfo() { //Prints name, age etc of object
super<Vehicle>.printInfo()
super<Fuel>.printInfo()
}
}
//Main.kt
var airplane : Airplane = Airplane(args)
var otherKerosin : Fuel = airplane
otherKerosin.fuelType = "Other Kerosin"
otherKerosin.printInfo()
airplane.printInfo()
otherKerosin.printInfo()
的输出类似于airplane.printInfo()
的输出,只是燃料类型不同。现在为什么要这样做,而不是创建新飞机并更改fuelType变量?
答案 0 :(得分:2)
此行
var otherKerosin : Fuel = airplane
不会创建某事物的新实例。它只是获得了对同一实例的新引用,但是将其类型缩小为Fuel接口。您使用otherKerosin
进行的任何更改也会更改分配给airplane
的原始飞机(反之亦然),因为这两个变量都指向同一实例。
在您给出的示例中,没有理由这样做。 otherKerosin
不必要地将其类型限制为Fuel
,这隐藏了Airplane
可能不属于Fuel
接口的额外功能。它没有为您提供原始airplane
引用无法提供的任何功能。但是,如果您要从某个函数返回飞机,而调用该函数的类仅需要使用Fuel
,则可能只想返回一个Fuel
,这样就不会暴露出比您更多的东西了。必须去外面的世界。例如:
interface FuelProvider {
fun provideFuel(): Fuel
}
class AirplaneProvider: FuelProvider {
override fun provideFuel(): Fuel = Airplane() // Airplane is cast to Fuel
}
几乎不需要转换为更窄类型的局部变量。但是有时您拥有的成员属性的类型比您手头拥有的对象的类型要窄,而您仍然希望将其分配给该属性。例如:
class FuelStorage(var fuel: Fuel? = null)
val storage = FuelStorage()
val airplane = Airplane()
storage.fuel = airplane // the Airplane is cast to Fuel to put it in the `fuel` property.
此处的FuelStorage
类并不关心其Fuel
是Airplane
还是其他类型的Fuel
。
我可以想到一个示例,您可能想在其中执行此操作,也就是说,如果您要编写的函数很长,并且想用一个变量来限制自己的能力,以使可用操作更简单。在很长的功能中,这可以帮助您跟踪自己在做什么。但是,如果某个函数的时间过长而不能真正起到帮助作用,则可能是代码的味道。
请注意,您在上面和我之前讨论过的转换类型是隐式转换,这是通过为实例匹配的属性或变量分配某些内容或返回来自动完成的来自返回类型为匹配项的函数中的某些内容。
您还可以使用as
或as?
来显式进行强制转换,当您要强制转换的类型与您要转换的类型不匹配时,可以执行从。例如,如果您有一个Fuel
,并且想要将其强制转换为Airplane
。 Fuel
并不总是Airplane
,因此必须显式进行强制转换以更改引用类型。如果基础实例实际上不是Airplane
,除非您使用安全的强制转换as?
,否则这将失败,并且例外。
您还可以通过if
检查本地变量是否属于某种类型来智能进行强制转换。检查之后,编译器可以假定该变量引用的是检查的类型。