JAVA堆、栈、方法区、StringBuffer与String的区别
前言:
上课提到的这么一个问题:
String, StringBuffer StringBuilder 的区别。
答:String 的长度是不可变的;
StringBuffer 的长度是可变的,如果你对字符串中的内容经常进行操作,
特别是内容要修改时,那么使用 StringBuffer,如果最后需要 String,那么使
用 StringBuffer 的 toString()方法;线程安全;
StringBuilder 是从 JDK 5 开始,为 StringBuffer 该类补充了一个单个线
程使用的等价类;通常应该优先使用 StringBuilder 类,因为它支持所有相同
的操作,但由于它不执行同步,所以速度更快。
助记:
其实由于随着电脑性能的提神以及业务需要,我们通常不怎么考虑线程安全问题而是速度问题,所以StringBuffer用的少为线程安全得那种!
对于可不可变联想到了 需要区分好堆、栈、方法区问题才能明白
字符串比较的问题:
补充知识:
1. 对于字符串:其对象的引用都是存储在栈中的,如果是编译期已经创建好(直接用双引号定义的)的就存储在常量池中,如果是运行期(new出来的)才能确定的就存储在堆中。对于equals相等的字符串,在常量池中永远只有一份,在堆中有多份
String s1 = "china";
String s2 = "china";
String s3 = "china";
String ss1 = new String("china");
String ss2 = new String("china");
String ss3 = new String("china");
面试题:
String s = new String(“xyz”);产生几个对象?一
个或两个,如果常量池中原来没有”xyz”,就是两个。
(先在常量池一个"xyz", 再在堆里面创建一个 new String("xyz"), 其中xyz 是由常量池拷贝过来
2. 对于基础类型的变量和常量 : 变量和引用存储在栈中,常量存储在常量池中。 ( 搞清楚什么是常量什么是变量。 常量就是final 的 不会变的, string 类型 其实也是 不可变类 所以在常量区。 )
int i1 = 9;
int i2 = 9;
int i3 = 9;
public static final int INT1 = 9;
public static final int INT2 = 9;
public static final int INT3 = 9;
3.对于成员变量和局部变量:(成员变量就是方法外部,类的内部定义的变量;局部变量就是方法内部定义的变量。局部变量必须初始化,成员变量jvm自动初始化, 形式参数也是局部变量)
局部变量的数据存在于栈内存中。栈内存中的局部变量随着方法的消失而消失。
成员变量存储在堆中的对象里面,由垃圾回收器负责回收。
class BirthDate {
private int day; //成员变量
private int month;
private int year;
public BirthDate(int d, int m, int y) { //d, m,y 也是局部变量
day = d;
month = m;
year = y;
}
省略get,set方法………
}
public class Test{
public static void main(String args[]){
int date = 9; //局部变量
Test test = new Test();
test.change(date);
BirthDate d1= new BirthDate(7,7,1970);
}
public void change1(int i){ //i 是局部变量
i = 1234;
}
解释:
1. date 是局部变量,基础类型, 所以值跟引用都放在栈里 int date = 9;
2. Test test = new Test(); test 为 new Test()对象的引用, 存放在栈里
3. test.change(date); i是局部变量,引用和值存在栈中。当方法change执行完成后,i就会从栈中消失。
4.4. BirthDate d1= new BirthDate(7,7,1970); d1 为对象的引用 所以存放在栈中, 其所指的对象 存放在堆中, ,其中d,m,y为局部变量存储在栈中,且它们的类型为基础类型,因此它们的数据也存储在栈中。day,month,year为成员变量,它们存储在堆中(new BirthDate()里面)。当BirthDate构造方法执行完之后,d,m,y将从栈中消失。
5.main方法执行完之后,date变量,test,d1引用将从栈中消失,new Test(),new BirthDate()将等待垃圾回收。
Java中数据的存储分为以上5种方式,但在实际中最常谈起的是:堆内存存储 与 栈内存存储。
我们可以联系着二者来分析这两种不同的存储方式,更利于我们理解:
首先,它们有一定的相同之处:
堆与栈都是用于程序中的数据在RAM(内存)上的存储区域。并且Java会自动地管理堆和栈,不能人为去直接设置。
其次,更关键的在于它们的不同之处:
1.存储数据类型:栈内存中存放局部变量(基本数据类型和对象引用),而堆内存用于存放对象(实体)。
2.存储速度:就存储速度而言,栈内存的存储分配与清理速度更快于堆,并且栈内存的存储速度仅次于直接位于处理器当中的寄存器。
3.灵活性:就灵活性而言,由于栈内存与堆内存存储机制的不同,堆内存灵活性更优于栈内存。
这样两种存储方式的不同之处,也是由于它们自身的存储机制所造成的。所以为了理解它们,首先我们应该弄清楚它们分别的存储原理和机制,在Java中:
— 栈内存被要求存放在其中的数据的大小、生命周期必须是已经确定的;
— 堆内存可以被虚拟机动态的分配内存大小,无需事先告诉编译器的数据的大小、生命周期等相关信息。
接下来便可以进行分析:
栈内存和堆内存的存储数据类型为何不同?
我们知道在Java中,变量的类型通常分为:基本数据类型变量和对象引用变量。
首先,8种基本数据类型中的数字类型实际上都是存储的一组位数(所占bit位)不同的二进制数据;除此之外,布尔型只有true和false两种可能值。
其次,对象引用变量存储的,实际是其所关联(指向)对象在内存中的内存地址,而内存地址实际上也是一串二进制的数据。
所以,局部变量的大小是可以被确定的;
接下来,java中,局部变量会在其自身所属方法(或代码块)执行完毕后,被自动释放。
所以局部变量的生命周期也是可以被确定的。
那么,既然局部变量的大小和生命周期都可以被确定,完全符合栈内存的存储特点。自然,局部变量被存放在栈内存中。
参考文献:
https://blog.csdn.net/DamonUp/article/details/88304467
相关文章
- java基础知识回顾之---java String final类之intern方法
- java基础知识回顾之---java String final类普通方法
- java实现遍历树形菜单方法——HibernateUtil实现
- java实现遍历树形菜单方法——Dao层
- java实现遍历树形菜单方法——映射文件VoteTree.hbm.xml
- Java实现 LeetCode 面试题62. 圆圈中最后剩下的数字(约瑟夫环)
- java实现输入日期
- Java实现 蓝桥杯 算法训练 关联矩阵
- java String/StringBuilder 方法
- Java使用正则表达式取网页中的一段内容(以取Js方法为例)
- JAVA实现多线程的两种方法
- java 11 标准Java异步HTTP客户端
- 【JAVA】 03-Java中的异常和包的使用
- Java多线程学习笔记 - 三、Thread类源码内的方法概览
- Java线程等待与唤醒案例(wait和notify方法使用)
- Java方法案例--比较两个值是否相等
- Atitit.视频文件加密的方法大的总结 java c# php
- 常见Java面试题 String 类的常用方法都有那些?
- java 当前系统时间(string日期格式和Date日期格式)加上天数怎么处理?两种方法
- 一文带你全面了解java对象的序列化和反序列化
- Java包装类中的equals方法
- Java中String类中compareTo( )方法
- Java复制文件用数据流方法,renameTO()方法是相当于剪切操作
- Java中的final变量 final修饰变量 final修饰方法 final修饰类 final和String的关系
- java日期和时间Date、Calendar、SimpleDateFormat
- (五)java进制
- java中集合类中Collection接口中的Map接口的常用方法熟悉
- Android获取Java类名/文件名/方法名/行号(四十)
- 循环遍历Java字符串字符的规范方法——类似python for ch in string
- java入门 常见问题0006:字符串的内容比较应当用String的equals方法,而不是用 ==