当前位置: 首页 > 面试题库 >

为什么我的实例初始化程序块在声明它之前可以引用一个字段?

喻珂
2023-03-14
问题内容

我的理解是,不能在声明变量之前引用变量,并且在创建对象时在构造函数之前按顺序执行在类主体内但在任何方法之外的所有代码(包括实例初始值设定项)
(例外是static变量和初始化程序块,它们在程序开始时按顺序运行,以初始化整个类)。那么,为什么以下代码会编译(并运行!):

public class WhyIsThisOk {
    { a = 5; } // why is this ok???
    int a = 10;

    public WhyIsThisOk() {
    }

    public static void main(String[] args) {
        WhyIsThisOk why = new WhyIsThisOk();
        System.out.println(why.a); // 10
    }
}

问题答案:

从文档:

Java编译器将初始化程序块复制到每个构造函数中。因此,该方法可用于在多个构造函数之间共享代码块。

上面的陈述有些误导,因为如果按照上面文档的解释,我们可以像这样重写原始代码:

public class WrongVersionOfWhyIsThisOk {

    int a = 10;

    public WhyIsThisOk (){
        a = 5;
    }

    public static void main(String[] args){
        WrongVersionOfWhyIsThisOk why = new WrongVersionOfWhyIsThisOk ();
        System.out.println(why.a);
    }
}

但是运行WrongVersionOfWhyIsThisOk将产生5而不是原始代码产生的10。

但是实际上,初始化程序块和变量赋值都被复制到构造函数中:

public class RightVersionOfWhyIsThisOk {

    int a;

    public RightVersionOfWhyIsThisOk (){
        a = 5;
        a = 10;
    }

    public static void main(String[] args){
        RightVersionOfWhyIsThisOk why = new RightVersionOfWhyIsThisOk ();
        System.out.println(why.a);
    }
}

更新:

这是文档,详细描述了初始化顺序和构造函数调用:

4)执行该类的实例初始化器和实例变量初始化器,并按照从左到右的顺序将实例变量初始化器的值在文本中显示在该类的源代码中,并将它们分配给相应的实例变量。如果执行这些初始化程序中的任何一个导致异常,则不会再处理其他初始化程序,并且该过程会因相同的异常而突然完成。否则,请继续执行步骤5。

5)执行此构造函数的其余部分。如果该执行突然完成,则出于相同原因,此过程也会突然完成。否则,此过程将正常完成。



 类似资料:
  • 问题内容: 假设一个项目包含几个类,每个类都有一个静态初始化程序块。这些块以什么顺序运行?我知道在一个类中,这样的块按照它们在代码中出现的顺序运行。我读过所有类都一样,但是我编写的一些示例代码对此表示不同。我使用以下代码: 并得到以下输出: START static - grandparent static - parent static - child instance - grandparen

  • 问题内容: 好像我遇到了本不应该出现的问题……但我想寻求帮助。 这里有一些我没有得到的解释。 具有两个简单的类,其中一个引用另一个,如下所示; 我收到注释的编译错误。有人可以告诉我该怎么办吗? 非常感谢任何好人的帮助! 问题答案: 正如 vadian 正确指出的 那样, 您应该在以下情况下创建一个: 您不能为 依赖 于另一个实例属性的存储属性提供默认值。

  • 本文向大家介绍请解释下为什么我们可以在声明函数前使用它?相关面试题,主要包含被问及请解释下为什么我们可以在声明函数前使用它?时的应答技巧和注意事项,需要的朋友参考一下 js 两个特性, 提升变量声明和函数声明,但是注意一点的是 这个是不叫函数声明的, 变量funcName还是会提升,只不过作为一个undefined的变量, 只有 这个叫函数声明,会被提升

  • 问题内容: 阅读其他人的代码,我已经看到很多: 我的问题是:用这种方式实例化它们的目的/优点是什么,而不是: 令我感到奇怪的是,我从未见过类似的东西: 要么 问题答案: 快速回答?使用接口和超类可以提高代码的可移植性和可维护性,主要是通过隐藏实现细节。采取以下假设示例: 我已经声明了一个帐户合同,该合同规定可以将已发布到该帐户的交易作为集合进行检索。我的代码的调用者不必关心我的方法实际上返回的集合

  • 它适用于我声明的结构xy。为什么相同的模式不适用于复杂的 错误消息: 我最好的猜测是这与