Q1)以下3个代码片段之间的差异是什么:为什么存在三种不同? (就内存分配而言)
Class C
{
StringBuffer sb = new StringBuffer();
C(){}
}
Class C
{
StringBuffer sb;
C()
{
sb = new StringBuffer();
}
}
Class C
{
C()
{
StringBuffer sb = new StringBuffer();
}
}
Q2)如何在没有任何参考变量的情况下创建对象。 例如, new C(); new C()。Hello(); 如何理解他们的内存管理,默认值,范围!!
Q3)以下2个片段之间的差异:
Class C
{
int a;
C(){}
}
Class C
{
C(){int a;}
}
答案 0 :(得分:1)
Q1)片段1和片段2是等价的。如果类C
有多个构造函数,则会有所不同。在片段1变体中,您只需编写一次初始化,在片段2变体中,您需要在每个构造函数中编写它。
在片段3中,变量sb
是构造函数中的局部变量,只在那里可见。当构造函数结束时,StringBuffer
对象可以被垃圾收集。
Q2)无法维护,创建后可立即进行垃圾回收。在new C().Hello();
的情况下,只有在Hello()
方法退出时才保证对象存在。
Q3)片段1声明一个类字段,片段2是构造函数中的局部变量。
答案 1 :(得分:1)
Fragment1
和Fragment2
实际上是相同的。它们都具有相同的范围,并创建相同的对象。在后者中,这是在构造函数中完成的。这就是区别。在我看来,成员通常应该在构造函数中初始化。
Fragment3
范围不同。一旦构造函数结束,C
就会被垃圾收集。这是因为,当方法完成时,所有本地对象都被解除引用。一旦没有引用指向实例,垃圾收集器就会做它最擅长的事情。收集该死的垃圾。
存在三个不同的例子,因为......好吧......它们可以在几种不同的情况下使用。您可能有一个依赖于另一个成员的成员,因此只能在第一个成员之后初始化。
示例
public class Test
{
private A a;
private B b;
public Test()
{
b = new B();
// As you can see, b needs to exist first.
a = new A(b);
}
如何维护没有任何引用变量的对象。例如,new C(); new C()。Hello();如何理解他们的内存管理,默认值,范围!!
如果没有对象的引用,那么它将被垃圾收集。声明new A()
时,只要您使用它就存在。第二个程序跨过那行代码(或字节代码的集合),垃圾收集器再次清理。
Q3)以下2个片段之间的差异:
在第一个示例中,a
可以在类中的任何位置使用。这称为global variable
,或者更具体地称为instance variable
。在第二个示例中,您声明了一个local
变量。这意味着它只能在声明它的方法中使用。在这种情况下,构造函数。
答案 2 :(得分:0)
其他答案的补充:
如果创建了一个新对象,JVM将始终在正在运行的程序的堆中分配内存并将该对象放在那里。在所有示例片段中,生成的StringBuffer
对象将放在堆中。
使用new
关键字创建新对象也会返回对该对象的引用。可以将此引用分配给变量。这里是你的示例片段的不同之处。在片段1和片段2中,您将此引用分配给实例变量(aka字段),该变量是对象数据的一部分 - 这里是类C
的实例。因此,这些实例变量也驻留在堆中。只要还有对C
实例的引用 - 可能在您的main方法中 - 肯定会引用包含的StringBuffer
实例。
在片段3中,将此引用分配给局部变量。局部变量的内存分配在堆栈上,而不是堆上。当方法结束时,也将丢弃此内存分配。没有(本地)变量,可以保存对象的引用。
如果对象没有引用,则该对象被认为有资格进行垃圾回收。在您的片段3中,构造函数结束后StringBuffer
实例将是这种情况。请注意,Java垃圾收集器不会立即运行并删除所有垃圾。它将在JVM选择的适当时间运行。