由于静态初始化而调用的构造函数

时间:2013-05-12 14:16:39

标签: java static constructor static-initialization

我正在通过Bruce Eckel第4版的Java思考。在初始化&中清理,页面:189第二个段落中的第一个要点:

  

即使它没有显式使用static关键字,构造函数实际上也是一个静态方法。

我有以下代码:

class Bar {
    Bar() {
        System.out.println("Bar Creation");
    }
}

class Foo {
    static int x = 10;
    static Bar b = new Bar();

    Foo() {
        System.out.println("Foo Creation");
    }
}

public class Test { 
    public static void main(String[] args) {
        System.out.println(Foo.x);
    }
}

如果它说的是真的应该调用Foo的构造函数。我没有看到下面这段代码发生的事情。

输出结果为:

Bar Creation
10

有人可以澄清它是什么意思吗?

我尽力引用这本书。我不认为该陈述之前或之后的部分与该陈述在该问题的背景下有很大关联。

谢谢,

Gudge

6 个答案:

答案 0 :(得分:4)

没有理由因为你提到班级来调用Foo()。加载类时会调用静态初始值设定项,如static Bar b = new Bar();;静态方法由您的代码调用。

我猜这本书的意思是构造函数就像静态方法一样, dispatch 是静态的:也就是说,没有办法继承和覆盖构造函数和调用站点对于构造函数或静态方法,始终引用在编译时确定的某个特定类。

(构造函数的这种静态性是“工厂”对象的动机,它们在实例方法中构造对象。)

答案 1 :(得分:3)

只是因为您尚未创建Foo的新实例来访问它的静态字段x

如果您创建了new Foo(),则会调用构造函数代码。由于x是静态成员字段,不需要来创建持有者类的实例以访问该字段。

访问x的另一种方法是新Foo().x,但新的Object创建是不必要的。

“Bar Creation”打印的原因是,因为 Foo声明的静态字段已分配。有关初始化规范,请参阅JLS 12.4.1

答案 2 :(得分:1)

在创建新对象后调用构造函数。我不会称之为静态方法,因为它必须有一个实例,并且该实例可以通过默认this

访问
public class Main {
    public Main() {
        // static methods do not have a `this`
        System.out.println("Main called" + this.getClass());
    }

    public static void main(String... ignore) {
        new Main();
    }
}

如果您反编译字节代码,则可以看到static方法

$ javap -c -p -cp . Main
Compiled from "Main.java"
public class Main {
  public Main();
    Code:
       0: aload_0       
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
       7: new           #3                  // class java/lang/StringBuilder
      10: dup           
      11: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
      14: ldc           #5                  // String Main called 
      16: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      19: aload_0       
      20: invokevirtual #7                  // Method java/lang/Object.getClass:()Ljava/lang/Class;
      23: invokevirtual #8                  // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
      26: invokevirtual #9                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      29: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      32: return        

  public static void main(java.lang.String...);
    Code:
       0: new           #11                 // class Main
       3: dup           
       4: invokespecial #12                 // Method "<init>":()V
       7: pop           
       8: return        
}

注意:static方法有不同的修饰符。

答案 3 :(得分:1)

除非你在Foo类上调用new(),否则不会调用构造函数。由于新关键字在内部调用构造函数。您只需使用其名称访问类的静态字段,而无需创建实例。

答案 4 :(得分:0)

你是新手Foo,而你正在新建Bar作为Foo中的静态字段。您可以在类中访问静态变量,而无需构造它的实例。

答案 5 :(得分:0)

只有在使用new关键字时才会调用构造函数。由于您没有new Foo(),因此不会调用构造函数。