我按照以下代码进行对象初始化:
namespace PatternPractice
{
public class TestClass
{
private DecoratorClass decoratorClass;
public TestClass()
{
}
public void addTest()
{
decoratorClass = new DecoratorClass();
testMethod(decoratorClass);
}
public void testMethod(DecoratorClass d)
{
Console.WriteLine("Am doing to explain my question.");
}
}
}
我有以下问题:
一个。什么是decoratorClass变量?对创建此变量的内存位置的引用或其他内容?
湾在addTest()方法中,我初始化了这个decoratorClass,它现在变成了什么,对象的引用还是别的什么?
℃。如果这成为对象的引用,那么为什么我们在参数中使用ref in参数。如果decoratorClass不是引用,那么这个问题就不好了。
d。在testMethod()方法中,我知道创建并传递了一个decoratorClass的副本,它又是一个引用还是别的什么?
我对在运行时(ASP.NET或JVM等)结束时如何发生这一切感到困惑,基本上与内存中的对象创建有关。
是否有任何文章可以解释运行时如何创建对象以及如何将它们分配给内存。
感谢您的帮助。
答案 0 :(得分:2)
价值类型和参考类型的基本概念。
任何类型的变量(无论是值类型还是引用类型)在声明时都会被压入堆栈。
然而,它们之间的区别在于,在值类型的情况下,对象的值存储在堆栈中。然而,在引用类型的情况下,堆的地址存储在堆栈中。
请考虑以下陈述:
int a;
DecoratorClass decoratorClass;
现在,当这些语句运行时,这就是堆栈:
STACK:
Variable Value
a 0 // Since ints are assigned to 0 by default
decoratorClass NULL
现在,如果您尝试访问decoratorClass,例如decoratorClass.memberVariable = xyz;
等等,然后你会得到一个NullPointerException。
这是因为,decoratorClass只声明未初始化。只有在调用构造函数时才会初始化它。
所以当下面的语句运行时:
decoratorClass = new DecoratorClass();
1)内存在特定位置(地址)的堆上分配。以字节为单位分配的内存量取决于类定义(成员变量)
HEAP:
xEEEE00
xEEEE01
xEEEE02
xEEEE03
2)现在,由于某些内存被分配给对象,因此堆栈将使用内存的地址进行更新
STACK:
Variable Value
a 0 // Since ints are assigned to 0 by default
decoratorClass xEEEE00
现在,如果您尝试访问decoratorClass.memberVariable,则不会获得NullPointer异常,因为实例已初始化并且已在堆栈上分配内存位置。
现在回答您的问题:
a。什么是decoratorClass变量?对创建此变量的内存位置的引用或其他内容? 和强> b。在addTest()方法中,我初始化了这个decoratorClass,它现在变成了什么,对象的引用还是别的什么?
<强>答:强> 运行声明语句时,decoratorClass变量将被推送到堆栈。 堆栈上的值(应该是堆上的地址)将为null,因为堆尚未分配内存。 调用构造函数时,将在堆上分配内存。 堆栈现在将包含堆上的地址
让我在回答c之前回答d,因为我相信这样理解你会更简单。
d。在testMethod()方法中,我知道创建并传递了一个decoratorClass的副本,这又是一个引用还是别的?
<强>答:强> 通过上面给出的解释,在方法testMethod(DecoratorClass d)中,d是testMethod()的局部变量。但是d中的值是什么(即堆栈上的值)?它是decoratorClass的地址。所以局部变量d指向同一个堆,因此访问d的memberVariable会得到与访问decoratorClass的memberVariable相同的值。
现在,如果您创建一个新的DecoratorClass并将其分配给d,它将不会更改decoratorClass。所以d可能指向EEEE06,但decoratorClass仍将指向EEEE00。
现在让我们转到c。
c。如果这成为对象的引用,那么为什么我们要使用ref in参数来传递参数。如果decoratorClass不是引用和其他东西,这个问题并不成立。 的答:强> 让我们考虑相同的方法testMethod(ref DecoratorClass d)。由于您将d作为ref传递,因此它不再是局部变量,而是它的相同变量。
现在,如果您创建一个新的DecoratorClass并将其分配给d,它将改变decoratorClass。因此d将指向EEEE06,但是decoratorClass的效果也指向EEEE06,因为两者都是堆栈中的相同变量。
有关通过ref v / s传递对象的传递对象的更多详细信息,请查看Memory games
希望我能够精心准备。
干杯!
答案 1 :(得分:1)
一个。如果DecoratorClass是一个类 - 那么是的,它是一个引用。如果它是一个struct,则类TestClass包含DecoratorClass的整个实例。
湾见“a”
℃。当您想要更改实际引用时使用ref,而不仅仅是它引用的对象
d。如果DecoratorClass是类,那么只复制它的引用并传递给testMethod。如果是struct - 则整个实例被复制并传递给testMethod
答案 2 :(得分:0)
一个。在您的类的顶部,Decoratorclass只是一个没有分配内存的变量。对象在堆上创建,而不是在堆栈上创建。
湾在testmethod中,你现在已经为堆上的这个DecoratorClass对象分配了内存,你的变量decoratorClass成为对堆上分配的内存的引用。
℃。 Ref参数主要用于传递值类型,例如(int,long,char等)。如上所述,如果要更改对象在内存中引用的内容,可以使用Ref传递对象(引用类型)。现在,您可以更改该对象引用的内容。
d。如上面的答案,只传递参考。因此,对该对象所在位置的引用是在Heap上传递的,这样在传递它时就无法改变。如果使用Ref传递它,您可以更改它引用的内容。现在您只能更改它包含的数据。