【问题标题】:Kotlin/Java, string array not yet initialized at method callKotlin/Java,字符串数组尚未在方法调用时初始化
【发布时间】:2017-03-24 15:29:25
【问题描述】:

在我的一个程序中,我遇到了一个空异常并调试了代码,我发现这是因为我的 String array (java) 之一:

val FRAGMENTS = arrayOf("phong-lighting", "phong-only", "blinn-lighting", "blinn-only")

当我在连续的class method (java) 中需要它时尚未初始化:

fun initializePrograms(gl: GL3) {

    programs = Array(LightingModel.MAX, {
        ProgramPairs(
                ProgramData(gl, "pn.vert", FRAGMENTS[it] + ".frag"),
                ProgramData(gl, "pcn.vert", FRAGMENTS[it] + ".frag"))
    })
    unlit = UnlitProgData(gl, "pos-transform.vert", "uniform-color.frag")
}

如果我把它移到里面:

fun initializePrograms(gl: GL3) {
    val FRAGMENTS = arrayOf("phong-lighting", "phong-only", "blinn-lighting", "blinn-only")
    ...
}

然后一切都很好..为什么?

Ps:同样的代码和同样的行为在 java 中也一样

编辑:不要混淆,init 不是class init,它扩展了Framework 方法here

Edit2:initializePrograms() 不会从超级构造函数中调用。它是从init(GL3 gl) 调用的,它覆盖Framework.init(GL3 gl) which gets called from Framework.init(GLAutoDrawable autoDrawable),它应该在开始时从Animator 调用一次,应该是另一个线程。

【问题讨论】:

  • 不是在超级构造函数内部调用了类方法吗?如果是,那么原因是在属性初始化之前调用了超级构造函数。
  • 是的,我认为并检查了它,但我认为它没有。这对我来说有点神秘。
  • 我对Kotlin了解不多,能不能用关键字来识别变量,不管是私有的还是公有的,在方法之外,看看是否有效?
  • @hotkey 不,它不会。initializePrograms()init(GL3 gl) 调用,它会覆盖从 Framework.init(GLAutoDrawable autoDrawable) 调用的 Framework.init(GL3 gl),它应该从 Animator 调用一次在开始时应该是另一个线程。
  • @In-youngChoung,你可以看看并行的java代码(括号里有引用)

标签: java exception null kotlin


【解决方案1】:

原因

如果在超类构造函数中调用方法initializePrograms,则崩溃是预期行为。类的属性在构造对象后初始化,因此在此之前它们是未初始化的。

在这种情况下,因为arrayOf函数是一个内联函数,它在反编译的类上清晰可见:

public final class Test {
   @NotNull
   private final String[] FRAGMENTS;
   ...

   public Test() {
      super();
      String[] elements$iv = new String[]{"phong-lighting", "phong-only", "blinn-lighting", "blinn-only"};
      Object[] var4 = (Object[])elements$iv;
      this.FRAGMENTS = (String[])var4;
   }
}

注意Test 类的构造函数以及调用super() 后属性是如何初始化的。

请注意,如果您使用非内联函数来初始化该属性(例如listOf),则初始化将与声明相结合,但这实际上是同一件事,只是没有那么明确。在 Java 中,这个字段也会在构造函数完成后被初始化。

public final class Test {
   @NotNull
   private final List FRAGMENTS = CollectionsKt.listOf(new String[]{"phong-lighting", "phong-only", "blinn-lighting", "blinn-only"});
   ...
}

解决方案

您最可能想要实现的目标(考虑到所有大写 FRAGMENTS)是将 then 声明为静态字段。在 Kotlin 中,您可以通过将其嵌套在特定类中的 companion object 中来做到这一点。

class Test {
    ...
    companion object {
        val FRAGMENTS = arrayOf("phong-lighting", "phong-only", "blinn-lighting", "blinn-only")
    }
}

然后,正如您在反编译的类中看到的那样,它被声明为静态字段并在 static 块中初始化:

public final class Test {
   @NotNull
   private static final String[] FRAGMENTS;
   ...

   static {
      String[] elements$iv = new String[]{"phong-lighting", "phong-only", "blinn-lighting", "blinn-only"};
      FRAGMENTS = (String[])((Object[])elements$iv);
   }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-08-23
    • 2020-04-14
    • 1970-01-01
    • 2022-11-22
    • 2017-09-14
    • 2021-10-13
    • 2022-07-05
    相关资源
    最近更新 更多