代码之家  ›  专栏  ›  技术社区  ›  ericn

Kotlin类应具有单个无参数构造函数

  •  0
  • ericn  · 技术社区  · 5 年前

    我使用以下方法实例化我的对象:

    val payInCurrency = Currency::class.createInstance()
                .copy(code = "GBP")
    

    但我在那条线上得到了一个例外:

    java.lang.IllegalArgumentException: Class should have a single no-arg constructor: class com.abc.Currency
        at kotlin.reflect.full.KClasses.createInstance(KClasses.kt:281)
        at com.abc.MyInteractorTest.setUp(MyInteractorTest.kt:55)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
        at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
        at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
        at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
        at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
        at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
        at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
        at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
        at org.mockito.internal.runners.DefaultInternalRunner$1.run(DefaultInternalRunner.java:79)
        at org.mockito.internal.runners.DefaultInternalRunner.run(DefaultInternalRunner.java:85)
        at org.mockito.internal.runners.StrictRunner.run(StrictRunner.java:39)
        at org.mockito.junit.MockitoJUnitRunner.run(MockitoJUnitRunner.java:163)
        at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.runTestClass(JUnitTestClassExecutor.java:106)
        at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:58)
        at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:38)
        at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.processTestClass(AbstractJUnitTestClassProcessor.java:66)
        at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51)
        at sun.reflect.GeneratedMethodAccessor35.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
        at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
        at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
        at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
        at com.sun.proxy.$Proxy2.processTestClass(Unknown Source)
        at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:117)
        at sun.reflect.GeneratedMethodAccessor34.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
        at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
        at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:155)
        at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:137)
        at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:404)
        at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
        at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
        at java.lang.Thread.run(Thread.java:748)
    
    3 回复  |  直到 5 年前
        1
  •  3
  •   Geoffrey Wiseman    5 年前

    你在打电话 createInstance() documentation 对于这种方法来说:

    创建类的新实例,调用一个没有参数或所有参数都是可选的构造函数(请参见kParameter.Isoptional)。如果没有或有许多这样的构造函数,则抛出异常。

    你在打电话给 createInstance 在类和抛出指定的异常时,该类也可以:

    • 没有没有没有参数的构造函数(或所有参数都是可选的)
    • 有多个构造函数符合该定义
        2
  •  3
  •   Roland    5 年前

    要么确保 data class initializes 所有值(因此将提供默认构造函数)或提供适当的默认值 constructor 你自己:

    // setting default values on all properties:
    data class Currency(val code : String = "GBP" / * all other properties need to have a default value assigned too */)
    
    // or add a default constructor:
    data class Currency(val code : String /* other properties */) {
      constructor() : this("GBP" /* other properties default values */)
    }
    

    注意 createInstance 使用 singleOrNull 在内部,如果存在超过1个(或无)的构造函数,并且满足仅具有可选参数的条件,则抛出异常。因此,如果您有几个这样的构造函数,或者您不想更改 Currency -类,然后迭代可用的构造函数,使用适合并填充参数的构造函数。你甚至可以跳过这个 copy -打电话。

    为什么还要使用这种方法来复制数据? 复制 只有当已经有了一个对象,您只想更改一些属性,而不想更改其他属性时,这才有意义,而且您的示例甚至可以这样写:

    val payInCurrency = Currency(code = "GBP")
    

    你已经知道你想要一个 货币 你也知道你希望代码是 "GBP" .

        3
  •  0
  •   ericn    5 年前

    很抱歉弄混了,谢谢你的帮助。
    事实上,很明显 KClasses.createInstance() 要求类具有“no arg构造函数”。

    因此,1个解决方案是更改类以引入“no arg构造函数”。

    另一个解决方案是使用我自己的 createInstance() 它接受没有“no arg constructor”的类。结果我的团队已经有了我们自己的团队 创建实例() 我用了错误的方法( kClasses.CreateInstance()。 )