关于Java栈与堆的思考
1.堆栈和堆是Java在Ram中存储数据的地方。与C++不同,Java自动管理堆栈和堆,程序员不能直接设置堆栈或堆。
2.栈的好处是访问速度比堆快,仅次于直接位于CPU中的寄存器。但缺点是必须确定堆栈中数据的大小和生命周期,这是不灵活的。此外,堆栈数据可以共享,详见第3点。堆的优点是内存大小可以动态分配,堆的生存期不必提前告诉编译器。Java垃圾收集器会自动收集这些未使用的数据。但缺点是由于运行时内存的动态分配,访问速度较慢。
3.Java中有两种类型的数据。
一种是原语类型,有八种类型,分别是int、short、long、byte、float、double、boolean、char(注意没有string这种基本类型)。这种类型由如下定义来定义:int a = 3;长b = 255L的形式,称为自动变量。值得注意的是,自动变量存储的是文字值,而不是类的实例,也就是对类的引用。这里没有课。例如int a = 3;a这里是对int类型的引用,指向文字值3。数据的这些文字值,由于其已知的大小和生命期(这些文字值在一个程序块中是固定的,程序块退出后字段值就消失了),为了速度而存在于堆栈中。
另外,栈还有一个很重要的特殊性,就是栈中的数据是可以共享的。假设我们同时定义:
int a = 3;
int b = 3;
编译器处理int a = 3;第一;首先,它将在堆栈中创建一个变量为A的引用,然后查找是否存在文字值为3的地址。如果找不到,它会打开一个存放文字值3的地址,然后将A指向3的地址。然后处理int b = 3;;在创建了B的引用变量后,因为栈中已经有了3的文字值,直接将B指向3的地址。这样,a和b都同时指向3。
特别是这种文字引用不同于类对象的引用。假设两个类对象的引用同时指向一个对象,如果一个对象引用变量修改了这个对象的内部状态,另一个对象引用变量会立即反映这个变化。相反,通过引用修改一个字面值的值不会导致指向这个字面值的另一个引用的值的改变。比如我们定义了A和B的值之后,设A = 4;那么,b将不等于4,而是等于3。在编译器内部,遇到了a = 4;当,它会重新搜索栈中是否有文字值4,如果没有,重新打开地址存储4的值;如果它已经存在,直接将A指向此地址。因此,A的值的变化不会影响b的值。
另一种是包装类数据,如Integer、String、Double等,包装相应的基本数据类型。所有这些类数据都存在于堆中。Java是用new()语句显式告诉编译器的,而且是在运行时根据需要动态创建的,所以很灵活,但缺点是耗时较多。4.字符串是一种特殊的包装数据。即可以使用String str = new String(" ABC ");表单创建时,也可以使用string str = " ABC的形式(相比之下,在JDK 5.0之前,你从未见过整数I = 3;因为类和文字不是通用的,String除外。在JDK 5.0中,这种表达是可以的!因为编译器在后台转换Integer i = new Integer(3)。前者是创建一个标准类的过程,即在Java中,一切都是对象,对象是类的实例,都是以new()的形式创建的。Java中的一些类,比如DateFormat类,可以通过它的getInstance()方法返回一个新创建的类,这似乎违背了这个原则。其实不是,这个类使用singleton模式返回类的一个实例,只不过这个实例是通过new()在类内部创建的,getInstance()从外部隐藏了这个细节。为什么在string str = " ABC在中,实例不是由new()创建的。是否违背上述原则?其实没有。
5.关于String str = "abc "的内功。Java在内部将该语句转换成以下步骤:
(1)首先给String类定义一个名为str的对象引用变量:stringstr
(2)找出栈中是否有一个值为“abc”的地址,如果没有,就开辟一个字值为“abc”的地址,然后新建一个String类的对象O,将O的字符串值指向这个地址,在栈中这个地址旁边写下这个被引用的对象O。如果已经有一个值为“abc”的地址,则查找对象O并返回O的地址。
(3)将str指向对象o的地址。
值得注意的是,一般情况下,String类中的字符串值是直接存储的。但是像string str = " ABC在这种情况下,字符串值是对存储在堆栈中的数据的引用!
为了更好地说明这个问题,我们可以用下面的代码来验证。
String str1 = " abc
String str 2 = " ABC ";
system . out . println(str 1 = = str 2);//真
注意,我们在这里没有使用str 1 . equals(str 2);因为这样会比较两个字符串的值是否相等。= = number,根据JDK的说明,只有当两个引用指向同一个对象时,才返回真值。这里我们想看的是str1和str2是否都指向同一个对象。
结果显示JVM创建了两个引用str1和str2,但只有一个对象,并且两个引用都指向这个对象。
让我们更进一步,将上面的代码改为:
String str1 = " abc
String str 2 = " ABC ";
str 1 = " BCD ";
System.out.println(str1 +","+str 2);//bcd,ABC
system . out . println(str 1 = = str 2);//假
也就是说,赋值的变化导致类对象引用的变化,str1指向另一个新对象!而str2仍然指向原始对象。在上面的例子中,当我们将str1的值改为“bcd”时,JVM发现堆栈中没有存储这个值的地址,于是它打开了这个地址,并创建了一个新对象,其字符串值指向这个地址。
位律师回复
0条评论