为什么可以在其定义中实例化类?

McG*_*one 26 java

一位同事(他是Java的新手)今天停下来问了一个看似简单的问题.不幸的是,我做了一个非常可怕的工作,试图向他解释.他有一本书有一些看起来像这样的代码:

class XCopy {

    public static void main(String[] args) {
        XCopy x = new XCopy(); // 1
        x.doIt();
    }

    public void doIt() {
        // Some code...
    }
}
Run Code Online (Sandbox Code Playgroud)

他在第1行感到困惑.他想知道的是为什么可以在XCopy类的定义中创建一个新的XCopy实例.他认为这会产生某种前向引用错误.毕竟,我们还没有宣布XCopy类是什么,所以我们怎么能创建一个呢?

我当然知道这是有效的代码,但是,当我试图向他解释时,我发现自己磕磕绊绊的答案,我担心他比他开始时更加困惑.我想听听其他解释为什么会这样.

有什么想法吗?为什么你可以在类的定义中实例化一个类的实例呢?

Mat*_*ard 35

您正在编译时定义类,其所有字段和方法等.直到运行时才创建实例.所以没有矛盾,课程完全由你到达第1行的时间来定义.

正如其他人指出的那样,因为该main方法是static在没有实例化对象的情况下到达第1行,但是你可以毫无问题地这样做.我一直用这种模式进行一类实验.

  • 什么是“一类实验”? (2认同)
  • @Andru当你正在尝试使用该语言时,你不想创建一个完整的程序,所以你只需将所有内容放入一个类中,包括main方法 (2认同)

Dav*_*sta 13

因为代码是先编译的,然后再执行.所有编译器都需要知道验证该行是否存在名为XCopy的类,并且它具有无参数构造函数.它不需要知道关于班级的一切.


duf*_*ymo 5

它不是C/C++意义上的前向引用.您的主要方法是将类作为其自身上下文中的类型引用.你没有"领先"任何东西.

main是静态的事实并不是密切相关的,因为即使对于非静态方法它仍然可以工作:

public class Foo
{
   private String x;

   public Foo(String x) { this.x = x; }
   public Foo(Foo f) { this.x = f.x; }  // copy constructor; still compiles fine, even without static
}
Run Code Online (Sandbox Code Playgroud)

一个区别是编译和链接.C/C++有单独的编译和链接步骤.Java有一个类加载器.我认为使用类加载器编译为字节代码并在运行时根据需要加载是Java和C/C++之间的细微差别,这解释了为什么不需要前向引用的想法,但我不确定.


Kim*_*ard 5

类只是一个蓝图,描述了类的每个实例的外观和行为。根据类及其构造函数的可见性,同一类、同一包中的代码或完全陌生的代码可能会创建实例。

例如,在构造函数不应公开的类中提供工厂方法是很常见的:

public class Foo {
    // only I get to create new instances
    private Foo() {
    }

    // but you can get instances through this factory method
    public static Foo createFoo() {
        return new Foo();
    }
}
Run Code Online (Sandbox Code Playgroud)