无意间在CSDN上看到一篇说栈与堆的文章,欣然取之,后来发现里面有些东西确实还有待推敲。

再看看评论,看到了高手的详解。我整合了一下,加上自己的理解,现在贴上来,希望多多赐教。

1. 栈(stack)与堆(heap)都是Java用来在Ram中存放数据的地方。与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆。

2. 栈的优势是,存取速度比堆要快,仅次于直接位于CPU中的寄存器。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是,由于要在运行时动态分配内存,存取速度较慢。

3. Java中的数据类型有两种。

一种是基本类型(primitive types), 共有8种,即int, short, long, byte, float, double, boolean, char(注意,并没有string的基本类型)。这种类型的定义是通过诸如int a = 3; long b = 255L;的形式来定义的,称为自动变量。值得注意的是,自动变量存的是字面值,不是类的实例,即不是类的引用,这里并没有类的存在。

如int a = 3;

直接在栈中把3这个字面值交给a。由于大小可知,生存期可知(这些字面值固定定义在某个程序块里面,程序块退出后,字段值就消失了),出于追求速度的原因,就存在于栈中。

但有特殊情况:

Integer a = 3;

Integer b = 3;

System.out.println(a==b);  //打印结果是true

但是,如果 Integer a = 266;Integer b = 266;System.out.println(a==b)  ///这样就是false了

原因:

Integer i = 3;
sun的编译器是这样处理的:
Integer i=Integer.valueOf(3);
而不是通过new来创建了,因为Integer类中静态的创建了-128~+127之间的对象,需要的数在这个范围之内时,直接返回,此范围之外的数才通过new来创建.

这里:要插入一点我对"=="号和"equals"的理解。

对于==,假如是a==b  那么,它是直接比较a与b里面的内容。

而对于equals:它是比较a与b所真实代表的值,是否相等。

4. String是一个特殊的类。即可以用String str = new String("abc");的形式来创建,也可以用String str = "abc";的形式来创建。

对于new的形式,大家应该想法都比较一致,它是在堆中开一片内存。只要见到new,就一定是在堆中开辟了空间。另外要注意,如果是一个类,它里面有基本类型,则基本类型也放在堆中。

着重说一下对于:String str = "abc"的内部工作。Java内部将此语句转化为以下几个步骤:

如果不用new的形式,则我们要分析的空间不再是堆,而是数据区了。在JVM中,一共分为四个部分:堆,栈,数据区,代码区。

首先呢,它应该在栈中开辟一个空间,名字就是str了。然后,java会到数据区中找值为abc的字符串,如果找到了,则把它的地址赋给栈中的已开辟空间的值。否则,它会先在数据区中开辟一块内存,值为abc,然后,再把它的地址赋给str.

为了更好地说明这个问题,我们可以通过以下的几个代码进行验证。
String str1 = "abc";  
String str2 = "abc";  
System.out.println(str1==str2); //true

注意,我们这里并不用str1.equals(str2);的方式,因为这将比较两个字符串的值是否相等。

==号,根据JDK的说明,只有在两个引用都指向了同一个对象时才返回真值(也就是说里面的存的地址是相同的)。而我们在这里要看的是,str1与str2是否都指向了同一个对象。

结果说明,JVM创建了两个引用str1和str2,但只创建了一个对象,而且两个引用都指向了这个对象。  
我们再来更进一步,将以上代码改成:
复制内容到剪贴板代码:
String str1 = "abc";  
String str2 = "abc";  
str1 = "bcd";  
System.out.println(str1 + "," + str2); //bcd, abc  
System.out.println(str1==str2); //false  
这就是说,赋值的变化导致了类对象引用的变化,str1指向了另外一个新对象!而str2仍旧指向原来的对象。上例中,当我们将str1的值改为"bcd"时,JVM发现在栈中没有存放该值的地址,便开辟了这个地址,并创建了一个新的对象,其字符串的值指向这个地址。

事实上,String类被设计成为不可改变(immutable)的类。如果你要改变其值,可以,但JVM在运行时根据新值悄悄创建了一个新对象,然后将这个对象的地址返回给原来类的引用。这个创建过程虽说是完全自动进行的,但它毕竟占用了更多的时间。在对时间要求比较敏感的环境中,会带有一定的不良影响。

再修改原来代码:

String str1 = "abc";

String str2 = "abc";

str1 = "bcd";

String str3 = str1;  
System.out.println(str3); //bcd

String str4 = "bcd";  
System.out.println(str1 == str4); //true  
str3这个对象的引用直接指向str1所指向的对象(注意,str3并没有创建新对象)。当str1改完其值后,再创建一个String的引用str4,并指向因str1修改值而创建的新的对象。可以发现,这回str4也没有创建新的对象,从而再次实现栈中数据的共享。

我们再接着看以下的代码。
String str1 = new String("abc");  
String str2 = "abc";  
System.out.println(str1==str2); //false 创建了两个引用。创建了两个对象。两个引用分别指向不同的两个对象。

String str1 = "abc";  
String str2 = new String("abc");  
System.out.println(str1==str2); //false  
创建了两个引用。创建了两个对象。两个引用分别指向不同的两个对象。

以上两段代码说明,只要是用new()来新建对象的,都会在堆中创建,而且其字符串是单独存值的,即使与栈中的数据相同,也不会与栈中的数据共享。

5. 结论与建议:

(1)我们在使用诸如String str = "abc";的格式定义类时,总是想当然地认为,我们创建了String类的对象str。担心陷阱!对象可能并没有被创建!唯一可以肯定的是,指向String类的引用被创建了。至于这个引用到底是否指向了一个新的对象,必须根据上下文来考虑,除非你通过new()方法来显要地创建一个新的对象。因此,更为准确的说法是,我们创建了一个指向String类的对象的引用变量str,这个对象引用变量指向了某个值为"abc"的String类。清醒地认识到这一点对排除程序中难以发现的bug是很有帮助的。

(2)使用String str = "abc";的方式,可以在一定程度上提高程序的运行速度,因为JVM会自动根据栈中数据的实际情况来决定是否有必要创建新对象。而对于String str = new String("abc");的代码,则一概在堆中创建新对象,而不管其字符串值是否相等,是否有必要创建新对象,从而加重了程序的负担。这个思想应该是享元模式的思想,但JDK的内部在这里实现是否应用了这个模式,不得而知。

(3) java新增了StringBuilder来处理可变字符串,如果不需要多线程环境,应该首先选择这个。

我理解的Java栈与堆,String类相关推荐

  1. Java本质论之关于Java栈与堆的思考

    来源:[http://www.csdn/1/2/3.com/html/20130308/83/80aa062b7f1f5537e075fa8893d4f189.htm] Java本质论之关于Java栈 ...

  2. Java里的字符串, String类简单介绍.

    String类在java面试中也是1个常见的问题点. 所以也是写在这里方便以后查阅了. 大家都知道c语言里是没有String 字符串这个数据类型的. 只能用字符数组的1个特殊形式来表示一个字符串, 就 ...

  3. 关于Java栈与堆的思考

    1. 栈(stack)与堆(heap)都是Java用来在Ram中存放数据的地方.与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆. 2. 栈的优势是,存取速度比堆要快,仅次于直接位于C ...

  4. java栈与堆_JAVA中的栈和堆

    JAVA在程序运行时,在内存中划分5片空间进行数据的存储.分别是:1:寄存器.2:本地方法区.3:方法区.4:栈.5:堆. 基本,栈stack和堆heap这两个概念很重要,不了解清楚,后面就不用学了. ...

  5. java栈与堆的区别

    栈与堆都是Java用来在RAM中存放数据的地方.与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆. Java的堆是一个运行时数据区,类的对象从中分配空间.这些对象通过new.newar ...

  6. java栈、堆、方法区

    1.java中的栈(stack)和堆(heap)是java在内存(ram)中存放数据的地方 2.堆区 存储的全部是对象,每个对象都包含一个与之对应的class的信息.(class的目的是得到操作指令) ...

  7. java栈和堆的区别_java 栈 和 堆 的区别

    转载: 一.java栈 Java 栈总是和线程关联在一起,每当创建一个线程时,JVM就会为这个线程创建一个对应的Java栈,在这个Java栈中又会含有多个栈(Frames),这些栈帧是与每个方法关联起 ...

  8. Java基本数据类型及String类

    基本类型,或者叫做内置类型,是JAVA中不同于类的特殊类型.它们是我们编程中使用最频繁的类型.java是一种强类型语言,第一次申明变量必须说明数据类型,第一次变量赋值称为变量的初始化. 一. Java ...

  9. java问题解读,String类为什么是final的

    一.理解final 望文生义,final意为"最终的,最后的",我理解为"不能被改变的",它可以修饰类.变量和方法. 所以我是否可以理解为被它所修饰的类.变量和 ...

最新文章

  1. UNet为什么在医学图像分割表现好?
  2. python 条件选择语句_Python趣味入门4:选择往往是最重要的-条件语句
  3. 如何获得Oracle系统性能统计? Oracle大型数据库系统在AIXUNIX上的实战详解 集中讨...
  4. 电网电压波形是否失真?
  5. oracle添加分区语句_按照子分区模板添加子分区
  6. 萤石云 服务器错误 10017
  7. 单例设计模式详解+源代码+JDK源码应用——Java设计模式系列学习笔记
  8. Ubuntu18.04 LTS 安装nvidia驱动出现Ignoring CC version mismatch
  9. MapReduce 支持的部分数据挖掘算法
  10. strike F1 to retry boot,F2 for setup utility
  11. 英世曼 | 动量是否具有行为性?
  12. Adobe Originals的可变字体
  13. C# 实现国密SM4加解密封装
  14. java两级缓存框架J2cache
  15. C语言程序设计-班级档案管理系统
  16. VR MultiPass\SinglePass(Instanced)\MultiView 浅析和区分总结
  17. 今天开始学Java 如果统计的个数相同,则按照ASII码由小到大排序输出 。
  18. 解决VSTO EXCEL 设置合并单元格锁定时报错问题
  19. 脏话越多,代码越好!
  20. RHCA-RH436 V1.1.12-PCS集群

热门文章

  1. leetcode oj java Bulls and Cows
  2. 【课程汇总】OpenHarmony 成长计划知识赋能第三期系列课程(附链接)
  3. Ubuntu16.04安装youtub_dl
  4. c#截屏木马,发送到邮箱
  5. 用于2D动画的实时嘴型同步技术
  6. 【基于python+Django的物品协同过滤音乐推荐系统-哔哩哔哩】 https://b23.tv/V2zN54R
  7. 基于Java Web技术的动车购票系统
  8. node-addon-api 的简单使用,c++数值、字符串、对象、数组转化为js可用数据。
  9. python画图颜色设置_python画图--输出指定像素点的颜色值方法
  10. js 公历日期转农历带节假日