【问题标题】:Why am I getting two different outputs in Java code为什么我在 Java 代码中得到两个不同的输出
【发布时间】:2015-03-28 12:43:15
【问题描述】:
class A {
    int xyz = new B().show(); // prints c=0 and z=null
    int c = -319;
    B z = new B();
    int lmn = z.show(); // prints c=-319

    class B {
        int show() {
            System.out.println("c=" + c);
            System.out.println("z=" + z);
            return -555;
        }
    }
}

class C {
    public static void main(String args[]) {
        A p = new A();
    }
}

为什么我最初收到c=0,然后是c=-319。同样,为什么 z 最初是 null 而之后不是 null。代码中发生了什么?

【问题讨论】:

  • 初始化按顺序进行,从上到下。如果你去掉 A 类并将逻辑粘贴到方法 a() 中,那么发生了什么应该是显而易见的。
  • 该语句 int xyz=new B().show() 不应该给出错误“非法前向引用”,因为 show() 使用了尚未分配内存的 c?
  • 为什么?那是另一个。如果只能引用按顺序声明的类,Java 确实是一种非常奇怪的语言……
  • 是的。但是它使用了 A 类的 c 变量,在这个阶段(xyz=new B().show())还没有在内存中创建。
  • 这正是leaking this in a constructor被认为是反模式的原因。

标签: java oop object inner-classes


【解决方案1】:

您需要知道 new 运算符负责创建类的 empty 实例(具有默认值的字段的实例:数字:0;布尔:false,字符:'\0',参考:null)。构造函数代码在new 完成其工作后调用,并负责为此类空对象设置正确的状态。

现在字段的初始化发生在构造函数中,所以你的代码

class A {
    int xyz = new B().show(); // prints c=0 and z=null
    int c = -319;
    B z = new B();
    int lmn = z.show(); // prints c=-319

    class B {
        int show() {
            System.out.println("c=" + c);
            System.out.println("z=" + z);
            return -555;
        }
    }
}

与(注意默认值)相同

class A {

    int xyz = 0;    //default values
    int c = 0;      //
    B z = null;     //
    int lmn = 0;    //

    A(){
        xyz = new B().show(); 
        c = -319;
        z = new B();
        lmn = z.show(); 
    }
    class B {
        int show() {
            System.out.println("c=" + c);
            System.out.println("z=" + z);
            return -555;
        }
    }
}

还有

xyz = new B().show();

一样
xyz = this.new B().show();

这样创建的B 实例将有权访问在当前A 构造函数中初始化的A 实例。但是初始化bz的代码

int c = -319;
B z = new B();

在您的第一个show() 方法(使用bz)之后发生,这意味着将显示它们的默认值。

第二个show()不存在这个问题

lmn = z.show(); 

因为现在 bz 已初始化。

【讨论】:

  • 感谢您倾倒它。让它变得如此清晰。干杯!
  • @user3678484 不客气 :) 顺便说一句,我添加了一些信息可能会让它更清晰。
【解决方案2】:

在您的line 2 中,您在开始时正在调用int xyz = new B().show(); // prints c=0 and z=null

哪些调用

class B {
        int show() {
            System.out.println("c=" + c);
            System.out.println("z=" + z);
            return -555;
        }
    }

在上面的代码中,您正在访问变量cZ,它们是类的成员变量,由于尚未初始化,它们被分配了默认值。

boolean                     =>  false
char                        =>  \u0000
int,short,byte / long       =>  0 / 0L
float /double               =>  0.0f / 0.0d
any reference type          =>  null

在您的情况下,ìnt 分配给 0,对象引用分配给 null :)

将您的 line 2 代码移动到 line 4 并且它应该打印,因为现在变量已初始化。

【讨论】:

    【解决方案3】:

    类实例化时有足够的内存来包含它的所有字段。

    当你这样做时:

    A p = new A();
    

    这将为 A 及其字段(xyz、c、z 和 lmn)分配内存。它们都以默认值分配在内存中(c 是 int 所以 0,z 是 object 所以 null [地址是 0x00])。

    当你运行时:

    int xyz = new B().show(); // prints c=0 and z=null
    

    您正在创建 B 的新实例。当该实例引用 c 和 z 时,它会打印它们的值。目前它们是默认值。出于所有意图和目的,show() 的观点是它引用的所有字段都已定义/声明,或至少 已分配

    那么当你执行时:

    B z = new B();
    int lmn = z.show(); // prints c=-319
    

    c 和 z 都获得了新值。但是在您的代码中的所有点,它们都已被分配并具有一定的价值(第一个默认值)。

    【讨论】:

      【解决方案4】:

      当您在 C 类中创建 A 的对象时

      A p = new A();
      

      默认构造获取类,并使用具有默认值的类成员变量创建对象。此时类变量的值如下:

      • xyz = 0(因为它是 int 类型)
      • c = 0(因为也是int)
      • z = null(因为它是参考)
      • lmn = 0(因为它是 int 类型)

      请参阅下面的屏幕截图以查看变量状态

      当达到以下评估 xyz 值的语句时:

      int xyz = new B().show()
      

      它会打印尚未完成初始化的 c 和 z 的值,因此我们将这些变量的默认值分别设为 0 和 NULL。

      第二次,程序调用B类的show()方法。所有变量初始化已经完成,因为下面的语句一直执行到我们到达z.show()

      int c = -319;
      b z= new (B); // call the default constructor of B to create object
      

      请参阅下面的屏幕截图以查看变量状态。

      因此,它将 C 的值打印为 -319,将 z 打印为对象的十六进制值。 (非空)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-01-08
        • 1970-01-01
        • 1970-01-01
        • 2021-03-31
        • 2021-03-23
        • 2017-06-22
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多