3

我读过一个类是创建对象的模型,并且在物理上不存在,而对象是真实的。但是我们在一个类中创建变量,甚至在操作它们。

  1. 当类在物理上不存在时,这怎么可能?

  2. 何时为这些变量创建内存?

  3. 为这些变量创建的内存在哪里?

4

4 回答 4

3

如果您的意思是静态类变量,则它们必须被初始化,并且类内的任何静态初始化代码都必须在使用该类之前运行。确切的时间,没有指定 IIRC,不同的 JVM 可能在不同的时间执行。它们基本上与具有这些的语言中的全局变量相同。

所以重申一下:静态的东西存在并在首次使用之前被初始化。JVM 实现会处理这个问题。

但是有一个对象:类对象的实例,它是类 Class的子类。


补充:事实上,在Java中类的存在是如此具体,以至于它们可以被序列化,通过网络传输到不同的JVM,在那里反序列化,在那里创建类的对象并执行代码。一个简单的例子是在浏览器中运行的普通 Java 小程序。另一个例子是 Jenkins/Hudson CI 系统中的从节点,从节点程序非常小,只包含接收、反序列化和实例化类和这些类的对象的代码,由它们连接到的主服务器发送。

于 2013-04-20T10:15:52.187 回答
3

试着这样想。这并不是对任何 Java 运行时如何做到这一点的准确解释,而是一种可能对您有所帮助的类/对象二元性的思考方式。

当你编写一个 X 类时,你同时描述了代码和数据。运行时将只需要一些东西的一个副本——例如代码和静态变量——以及其他东西的每个对象的一个​​副本,比如实例变量。您在编写的类文件中描述这两个东西,即使它们将分开存储。

将每个类一个副本的事物视为一起存储在一块内存中——它在 C 中称为结构。在 Java 中,第一次在程序中引用类 X 时,运行时分配这块内存并将其与类 X 相关联。

当程序执行诸如“X x1 = new X()”之类的语句时,运行时分配另一个包含所有实例变量的内存块(或结构),并保留一个指向与 x1 变量关联的单独指针。

现在,当程序执行“Arc arc = x1.getArc();”之类的东西时,运行时使用第一个指针来引用方法 getArc() 中的代码,第二个指针来引用与 x1 关联的实例变量,并使用这些实例变量执行指定的代码。

OO 编程提供了这种将数据与操作它的代码相关联的方式,允许我们将程序组织为组合代码和数据的“对象”。运行时为我们跟踪事物的不同副本。

而且我认为说该课程不存在是不准确的,它只是不会以您编写它的形式存在。

于 2013-04-20T11:43:48.393 回答
0

类在运行时确实存在于 JVM 中。您阅读的解释是试图解决 A 点,而将其余细节留待以后处理。学校和书籍一直在这样做。

在 Oracle JVM 中,类从加载的那一刻起就具有物理表示。事实上,每个对象都有一个指向该类的指针,并且许多对象可以指向同一个类。

于 2013-04-20T13:58:59.833 回答
0

我不会将类或对象视为物理事物,这让我感到困惑。类通常被描述为对象的蓝图。对象必须使用new关键字来实例化(创建),当对象被实例化时,对象的类被用作创建基本默认对象的蓝图。然后,即使在运行时,也可以通过引用内存中存储对象的位置并使用对象类中的方法来操作对象类中的字段来操作对象,至少这是通常应该这样做的方式,它的所谓的封装,在 OOP 中非常重要,所以如果您不熟悉封装,我建议您研究一下。

我提到对象可以在运行时被操作,这是对象和类之间的主要区别。类也可以使用称为反射的东西,但这是另一天的另一个话题。变量或字段有时被描述为地址,它是对存储对象的内存位置的引用。对象不是直接访问的,它们是通过变量引用的。

JLabel label;

上面的代码在使用关键字JLabel实例化对象时在内存中留出一个位置来存储对象。new到目前为止,还没有创建对象,我们已经声明了一个变量,它是对内存中创建对象时将存储的位置的引用。我们不会直接访问我们的 JLabel 对象,我们将使用我们创建的“标签”变量来引用内存中的实际对象。所以如果我们创建两个JLabel对象并实例化它们,像这样......

JLabel label;
label = new JLabel();
JLabel anotherLabel = new JLabel("this is another label");

我们现在有两个 JLabel 对象。第一个对象首先声明一个变量来引用该对象,然后在单独的行上实例化它。第二个对象声明了对它的引用并将其全部实例化在一行中。您可以通过任何一种方式创建对象,并且使用这两种方法有不同的原因。当一个对象被创建时,它的至少一个构造函数被调用,第一个对象调用JLabel类内部的不带参数的构造函数;第二个对象使用JLabel类中的构造函数,该构造函数接受 aString并创建显示传递给构造函数的文本的对象。

现在想象程序正在运行,我们想要更改第一个对象,使其显示一些文本,因为它当前是空白的,因为我们使用了不带任何参数的构造函数。我们可以使用这样的setText(String)方法来操作对象。

label.setText("now the first label displays text");

我们没有改变JLabel通过使用该方法以任何方式进行类,但是我们已经更改了对象,所以现在它显示文本。对于这个答案,我可能会失去一堆声望点,或者不管它们是什么,因为我可能没有完全正确地解释每个细节,但我回答了这个问题,因为你问的是我很难回答的问题理解了很长时间,可能比大多数人都理解,因为我从未上过编程课。有这么多,如果不写一本书,我可能无法完全解释这一点,所以我没有深入探讨范围、访问修饰符、静态等内容,但我试图涵盖我认为对于理解你是什么很重要的内容问。就像我说的,

哦,我忘了你的另一个问题。当创建对象的变量时,声明内存中存储对象的位置。此时有一个位置,但内存中的大小仍然为 0 或 null,因为没有对象。当对象被实例化时,实际存储对象所需的内存将被填充。

于 2013-04-20T15:28:22.903 回答