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

在类本身内部创建类的实例如何工作?

赵飞雨
2023-03-14
问题内容

什么使在类本身内部创建类的实例成为可能?

public class My_Class
 {

      My_Class new_class= new My_Class();
 }

我知道这是有可能的,而且我自己也做过,但是我仍然不能使自己相信这不像是“谁先是鸡还是蛋?” 问题类型。我很高兴收到一个可以从编程角度以及从JVM
/编译器角度阐明这一问题的答案。我认为理解这一点将帮助我清除OO编程中一些非常重要的瓶颈概念。

我已经收到了一些答案,但是还没有达到我期望的程度。


问题答案:

在类本身中创建类的实例绝对没有问题。在编译程序和运行程序时,可以通过不同方式解决明显的“鸡或蛋”问题。

编译时间

在编译创建自身实例的类时,编译器会发现该类对其自身具有循环依赖关系。这种依赖性很容易解决:编译器知道该类已经在编译,因此它不会尝试再次编译它。相反,它假装该类已经存在会相应地生成代码。

运行

类创建自身对象的最大问题是,该类甚至不存在。也就是说,当类被加载时。通过将类加载分为两个步骤来解决此问题:首先 定义 类,然后将其 初始化

定义意味着将类注册到运行时系统(JVM或CLR),以便它知道类对象具有的结构,以及在调用其构造函数和方法时应运行什么代码。

一旦定义了类,就将其初始化。这是通过初始化静态成员并运行静态初始化程序块以及用特定语言定义的其他操作来完成的。回想一下,此时已经定义了该类,因此运行时知道该类的对象是什么样,应该运行哪些代码来创建它们。这意味着初始化类时创建类的对象没有任何问题。

以下示例说明了Java中类初始化和实例化如何交互:

class Test {
    static Test instance = new Test();
    static int x = 1;

    public Test() {
        System.out.printf("x=%d\n", x);
    }

    public static void main(String[] args) {
        Test t = new Test();
    }
}

让我们逐步介绍JVM如何运行该程序。首先,JVM加载Test该类。这意味着首先 定义 了该类,以便JVM知道

  1. 一个叫做Testexist 的类,它具有一个main方法和一个构造函数,并且
  2. Test类有两个静态变量,一个叫x和另一个叫instance,和
  3. Test类的对象布局是什么?换句话说:一个对象看起来像什么;它具有什么属性。在这种情况下Test,没有任何实例属性。

现在定义了类,就将其 初始化了
。首先,将默认值0null分配给每个静态属性。设置x0。然后,JVM按源代码顺序执行静态字段初始化程序。那里有两个:

  1. 创建Test该类的实例并将其分配给instance。创建实例有两个步骤:
    1. 首先为对象分配了内存。JVM之所以可以这样做,是因为它已经从类定义阶段知道了对象的布局。
    2. Test()构造函数初始化对象。JVM之所以可以这样做,是因为它已经具有来自类定义阶段的构造函数代码。构造函数打印出的当前值x,即0
  2. 将静态变量设置x1

直到现在,该课程已完成加载。请注意,JVM创建了该类的实例,即使它尚未完全加载。你有这个事实证明,因为构造函数打印出初始默认值0x

现在,JVM已经加载了此类,它调用main方法来运行程序。该main方法创建另一个类对象Test-程序执行中的第二个对象。构造函数再次输出当前的值x,现在是1。该程序的完整输出为:

x=0
x=1

如您所见,这里没有鸡或蛋的问题:将类加载分为定义阶段和初始化阶段完全可以避免该问题。

当对象的一个​​实例想要创建另一个实例时(如下面的代码),该怎么办?

class Test {
    Test buggy = new Test();
}

当您创建此类的对象时,同样没有固有的问题。JVM知道如何将对象布置在内存中,以便可以为其分配内存。它将所有属性设置为其默认值,因此buggy设置为null。然后,JVM开始初始化对象。为此,它必须创建class的另一个对象Test。像以前一样,JVM已经知道该怎么做:它分配内存,将属性设置为null,并开始初始化新对象……这意味着它必须创建相同类的第三个对象,然后创建第四个对象。第五,依此类推,直到它耗尽堆栈空间或堆内存为止。

在这里,您不会有任何概念上的问题:这只是编写不良程序中无限递归的常见情况。可以使用例如计数器来控制递归;此类的构造函数使用递归来创建对象链:

class Chain {
    Chain link = null;
    public Chain(int length) {
        if (length > 1) link = new Chain(length-1);
    }
}


 类似资料:
  • 是什么使得在类本身内部创建类的实例成为可能? 我知道这是可能的,我自己也做过,但我仍然无法让自己相信这不是“谁是第一个——鸡还是蛋?”问题的类型。我很高兴收到一个答案,它将从编程角度以及JVM/编译器角度阐明这一点。我认为理解这一点将有助于我澄清OO编程中一些非常重要的瓶颈概念。 我收到了一些答案,但没有一个能达到我预期的程度。

  • 问题内容: 我是Java新手。 我的文件如下所示: 在另一个Java文件中,我试图创建A对象调用 但是由于某种原因我得到了错误: 有人可以解释我该怎么做吗?我的意思是,我真的需要创建的实例,然后设置实例,然后将实例提供给方法,还是有另一种方法呢? 问题答案: 在您的示例中,您有一个内部类,该内部类始终与外部类的实例绑定。 如果您想要的只是嵌套类以提高可读性而不是实例关​​联的一种方式,那么您需要一

  • 我是Java新手。 我的文件看起来像这样: 在另一个java文件中,我试图创建一个调用 但由于某种原因,我得到了一个错误: 有人能解释一下我怎么做我想做的事吗?我的意思是,我真的需要创建的实例,然后将其设置为,然后将的实例赋给该方法吗,还是有其他方法可以做到这一点?

  • 问题内容: 我想创建一个内部类的Spring Bean。如果我有以下内部类: 我想在我的XML配置文件中创建bean实例。 问题答案: 您不能使用点()表示法访问公共静态内部类,而应使用货币()。一个例子: 这将起作用。

  • 问题内容: 我正在创建一个类及其子类,需要在其中调用父级的静态方法以返回子级实例。 问题答案: 该静态方法被调用,其值是类对象,子类,你把它称为后的构造。因此,您可以使用实例化它:

  • 问题内容: 我有一个实用程序方法,当从中删除了不相关的逻辑时,简化的方法将如下所示: 问题是,如果是诸如的内部类,则该方法即使是公共方法也将不起作用,因为它将抛出。 有没有办法动态实例化内部类? 问题答案: 如果它是真正的 内部 类而不是 嵌套 (静态)类,则有一个隐式构造函数参数,它是对外部类实例的引用。在那个阶段您不能使用- 必须获得适当的构造函数。这是一个例子: