Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Kotlin 我如何强制一个类有一个伴生对象?_Kotlin - Fatal编程技术网

Kotlin 我如何强制一个类有一个伴生对象?

Kotlin 我如何强制一个类有一个伴生对象?,kotlin,Kotlin,我想要的是: 通常,Kotlin使用伴随对象而不是静态函数来解决问题。但是,接口不能定义对具有函数的伴随对象的需求。那么我如何才能做到这一点呢?使用此选项的代码如下所示 fun <T : base> bar() { T.foo() } 目标是我可以创建一个新的完整类Shape,并拥有与它如何构建该文件中包含的具体对象相关的所有逻辑,而不是使用一些单一的共享开关语句;TR: 我如何强制一个类有一个伴生对象 你不能 Kotlin没有静态方法。即使它有它们,它们也不会被重写,因为

我想要的是:

通常,Kotlin使用伴随对象而不是静态函数来解决问题。但是,接口不能定义对具有函数的伴随对象的需求。那么我如何才能做到这一点呢?使用此选项的代码如下所示

fun <T : base> bar() {
  T.foo()
}

目标是我可以创建一个新的完整类
Shape
,并拥有与它如何构建该文件中包含的具体对象相关的所有逻辑,而不是使用一些单一的共享开关语句;TR:

  • 我如何强制一个类有一个伴生对象
  • 你不能
Kotlin没有静态方法。即使它有它们,它们也不会被重写,因为它们不是Java语言。对伴生物体也是如此。Kotlin代码最终被编译成Java字节码,所以在Java中不可能实现的东西在Kotlin中也不可能实现

编辑:

很有意思的是,看看编译器对它有什么看法。考虑下面的片段:

open class Base {
    companion object {
        fun test() {}
    }
}

inline fun <reified T : Base> staticCall() {
    T.test() // <-- ERROR
}
开放类基类{
伴星{
趣味测试(){}
}
}
内联调用(){

T.test()/TL;TR

  • 我如何强制一个类有一个伴生对象
  • 你不能
Kotlin没有静态方法。即使它有静态方法,它们也不会被重写,因为它们不在Java中。对伴生对象也是如此。Kotlin代码最终被编译成Java字节码,因此Java中不可能的东西在Kotlin中也不可能实现

编辑:

很有趣的是,看看编译器有什么要说的。请考虑下面的片段:

open class Base {
    companion object {
        fun test() {}
    }
}

inline fun <reified T : Base> staticCall() {
    T.test() // <-- ERROR
}
开放类基类{
伴星{
趣味测试(){}
}
}
内联调用(){

T.test()//接口可以定义某个具有函数的对象的需求,并且您可以建议它作为伴随对象,即使您不能强制它

interface BaseCompanion {
    fun foo(): Unit
}

interface Base {
    companion object : BaseCompanion {
        fun foo() { println("in Base") }
    }

    fun companion(): BaseCompanion = Base
}

interface Derived : Base {
    companion object : BaseCompanion {
        fun foo() { println("in Derived") }
    }

    override fun companion() = Derived
}

// value parameter, not type parameter
fun bar(companion: BaseCompanion) {
    companion.foo()
}

bar(Base)
bar(Derived)
companion()
函数在本例中实际上没有使用,它用于从
Base
实例访问companion时:

fun baz(x: Base) {
    x.companion().foo()
}
另一个(不安全)选项是使用反射定义
companion()

fun companion() = this::class.companionObjectInstance as BaseCompanion

加号:无需在派生的
中显式重写它;减号:1.如果忘记创建伴星或扩展
BaseCompany
,将在运行时崩溃;2.比无反射定义慢。

接口可以定义某个具有函数的对象的需求,并且您可以建议它是伴星对象即使你不能强迫它

interface BaseCompanion {
    fun foo(): Unit
}

interface Base {
    companion object : BaseCompanion {
        fun foo() { println("in Base") }
    }

    fun companion(): BaseCompanion = Base
}

interface Derived : Base {
    companion object : BaseCompanion {
        fun foo() { println("in Derived") }
    }

    override fun companion() = Derived
}

// value parameter, not type parameter
fun bar(companion: BaseCompanion) {
    companion.foo()
}

bar(Base)
bar(Derived)
companion()
函数在本例中实际上没有使用,它用于从
Base
实例访问companion时:

fun baz(x: Base) {
    x.companion().foo()
}
另一个(不安全)选项是使用反射定义
companion()

fun companion() = this::class.companionObjectInstance as BaseCompanion

加:无需在
Derived
中显式重写它;减:1.如果忘记创建companion或扩展
BaseCompanion,将在运行时崩溃;2.比无反射定义慢。

根据您更新的问题,您想要的似乎通常是使用工厂模式实现的g> 。或者,您也可以使用依赖项注入。有许多选项不使用反射

为什么不使用反射

有几个原因,如果您用谷歌搜索它,您可以找到更多。通常,创建反射是为了特定目的,以发现在编译时未知的类的功能。您不使用反射,因为您的实现要求您了解该类,以便将其作为具体化的泛型参数传递。如果您确实需要在编译时发现您不知道的类,则可以使用依赖项注入

对于您的版本,更简单的解决方案是factory模式:

interface Shape
class Square : Shape
class Circle : Shape
class Sphere : Shape
class Cube : Shape

object ShapeFactory {
    fun build2DShape(sides: Int): Shape {
        if(sides > 0) Square() else Circle()
    }

    fun build3DShape(sides: Int): Shape {
        if(sides > 0) Cube() else Sphere()
    }
}

fun main() {
    println(ShapeFactory.build2DShape(0))
    println(ShapeFactory.build3DShape(0))
}
简而言之,
Build(0)
ShapeFactory.build3DShape(0)
替换。调用者仍然必须知道存在3dshape以及它们的位置。唯一改变的是不需要反射

fun companion() = this::class.companionObjectInstance as BaseCompanion
这要求调用函数的人知道2D和3D形状的存在。与反射实现中的情况相同。通过这种方式,您可以掌握如何在与形状相同的文件中创建形状的所有逻辑。如果愿意,您甚至可以让工厂调用形状的伴生对象中的某些函数。哟你的工厂知道这些子类的存在,但是由于你可以把工厂和子类放在同一个文件中,这就不会把逻辑分割到其他地方

如果要将决定是二维还是三维形状的任务委托给子类,可以执行以下操作:

interface Shape
class Square : Shape
class Circle : Shape
class Sphere : Shape
class Cube : Shape

object ShapeFactory {
    fun build2DShape(sides: Int): Shape {
        return if(sides > 0) Square() else Circle()
    }

    fun build3DShape(sides: Int): Shape {
        return if(sides > 0) Cube() else Sphere()
    }
}

fun getBuilder(dimensions: Int): (sides: Int) -> Shape {
    if (dimensions == 2)
        return ShapeFactory::build2DShape
    else 
        return ShapeFactory::build3DShape
}

fun main() {
    print (getBuilder(2)(3))
}

根据您更新的问题,似乎您想要的通常是使用工厂模式实现的。或者您也可以使用依赖项注入。有许多选项不使用反射

为什么不使用反射

有几个原因,如果您用谷歌搜索它,您可以找到更多。通常,创建反射是为了特定目的,以发现在编译时未知的类的功能。您不使用反射,因为您的实现要求您了解该类,以便将其作为具体化的泛型参数传递。如果您确实需要在编译时发现您不知道的类,则可以使用依赖项注入

对于您的版本,更简单的解决方案是factory模式:

interface Shape
class Square : Shape
class Circle : Shape
class Sphere : Shape
class Cube : Shape

object ShapeFactory {
    fun build2DShape(sides: Int): Shape {
        if(sides > 0) Square() else Circle()
    }

    fun build3DShape(sides: Int): Shape {
        if(sides > 0) Cube() else Sphere()
    }
}

fun main() {
    println(ShapeFactory.build2DShape(0))
    println(ShapeFactory.build3DShape(0))
}
简而言之,
Build(0)
ShapeFactory.build3DShape(0)
替换。调用者仍然必须知道存在3dshape以及它们的位置。唯一改变的是不需要反射

fun companion() = this::class.companionObjectInstance as BaseCompanion
这要求调用函数的人知道2D和3D形状的存在。与反射实现中的情况相同。这