什么使在类本身内部创建类的实例成为可能?
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知道
Test
exist 的类,它具有一个main
方法和一个构造函数,并且Test
类有两个静态变量,一个叫x
和另一个叫instance
,和Test
类的对象布局是什么?换句话说:一个对象看起来像什么;它具有什么属性。在这种情况下Test
,没有任何实例属性。现在定义了类,就将其 初始化了
。首先,将默认值0
或null
分配给每个静态属性。设置x
为0
。然后,JVM按源代码顺序执行静态字段初始化程序。那里有两个:
Test
该类的实例并将其分配给instance
。创建实例有两个步骤:
Test()
构造函数初始化对象。JVM之所以可以这样做,是因为它已经具有来自类定义阶段的构造函数代码。构造函数打印出的当前值x
,即0
。x
为1
。直到现在,该课程已完成加载。请注意,JVM创建了该类的实例,即使它尚未完全加载。你有这个事实证明,因为构造函数打印出初始默认值0
的x
。
现在,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实例。 问题答案: 您不能使用点()表示法访问公共静态内部类,而应使用货币()。一个例子: 这将起作用。
问题内容: 我正在创建一个类及其子类,需要在其中调用父级的静态方法以返回子级实例。 问题答案: 该静态方法被调用,其值是类对象,子类,你把它称为后的构造。因此,您可以使用实例化它:
问题内容: 我有几个函数需要精确的参数类型(又名): 我这样使用它们,效果很好: 但是我想知道是否有可能使代码更简洁,即 如果是这样,我应该放什么呢? 编辑: 1)我使用和作为简化示例。在我的实际代码中,我使用自定义类。 2)我需要知道我的函数中的确切类型(类),所以我不能 提前使用谢谢 问题答案: 您可以使用或者,这是双方共同的超类型和。 但是,泛型是不必要的: 等同于 删除后。 对于输入参数具