0

我正在阅读 Bruce Eckel 第 4 版的 Thinking in 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

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

我已尽力引用这本书。我认为该陈述之前或之后的部分与该问题的上下文中的该陈述没有太大关系。

谢谢,

古吉

4

6 回答 6

4

没有理由Foo()仅仅因为你提到了课程而被召唤。类加载时调用静态初始化器;static Bar b = new Bar();静态方法由您的代码调用。

我猜这本书的意思是构造函数就像静态方法,因为调度是静态的:也就是说,没有办法继承和覆盖构造函数,以及构造函数的调用站点或静态方法,总是指的是在编译时确定的某些特定类。

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

于 2013-05-12T14:23:38.697 回答
3

仅仅因为您还没有创建新实例Foo来访问x它的静态字段

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

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

而“Bar Creation”被打印出来的原因是,A static field声明的Foo被赋值。有关初始化规范,请参阅JLS 12.4.1

于 2013-05-12T14:18:22.013 回答
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方法有不同的修饰符。

于 2013-05-12T14:20:07.377 回答
1

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

于 2013-05-12T14:20:13.657 回答
0

您更新了 Foo,而不是将 Bar 更新为 Foo 中的静态字段。您可以访问类中的静态变量,而无需构造它的实例。

于 2013-05-12T14:27:02.307 回答
0

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

于 2013-05-12T14:31:41.383 回答