一、问题--现象
首先看一个问题:
代码段一:
classTesetNeicun{
public static void main(String[] args){
String str1="abc";
String str2 ="abc";
System.out.println(str1==str2);
}
}
结果:
代码段二:
classTesetNeicun{
publicstatic void main(String[] args){
Stringstr1 = new String("abc");
Stringstr2=new String("abc");
System.out.println(str1==str2);
}
}
二、原因 --解释
为什么会出现这种结果呢?我们先看Java中的堆和栈;当在一段代码块定义一个变量时,Java就在栈中为这个变量分配内存空间,当超过变量的作用域后,Java会自动释放掉为该变量所分配的内存空间,该内存空间可以立即被另作他用。堆内存用来存放由new创建的对象和数组。在堆中分配的内存,由Java虚拟机的自动垃圾回收器来管理。在堆中产生了一个数组或对象后,还可以在栈中定义一个特殊的变量,让栈中这个变量的取值等于数组或对象在堆内存中的首地址,栈中的这个变量就成了数组或对象的引用变量。引用变量就相当于是为数组或对象起的一个名称,以后就可以在程序中使用栈中的引用变量来访问堆中的数组或对象。
栈与堆都是Java用来在Ram中存放数据的地方。 Java的堆是一个运行时数据区,类的对象从中分配空间。堆是由垃圾回收来负责的,堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,因为它是在运行时动态分配内存的,Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是,由于要在运行时动态分配内存,存取速度较慢。
栈的优势是,存取速度比堆要快,仅次于寄存器,栈数据可以共享。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。栈中主要存放一些基本类型的变量(,int, short, long, byte, float, double, boolean, char)和对象句柄。
下面开始分析,代码段一,就是创建两个变量,变量是存在栈中的;代码段二其实java执行的时候是拆解为两条语句执行的:
String str1; //1
str1=new String(“abc”); //2
1. 在栈内存中定义一个名为str1的对String类的对像引用变量;
2. 在堆内存开辟了一块空间用于存放字符串“abc”,将1定义的引用变量str1指向该空间,其实真正是存在堆中的;str1和str2中存的是地址,他们指向不同的两块堆内存空间,所以str1==str2结果为false。
三、使用
下面看一个例子,看对象是如何new出来的:
代码:
class Cat{ privatedouble weight; privateint age; publicCat(double _weight,int _age){ this.weight=_weight; this.age=_age; } } publicclass CatDemo{ public static void main(String[] args){ Cat kitty =new Cat(3.0,2); } }
通过代码我们分析,kitty是如何new出来的:(1)先在栈内存中定义引用变量kitty,然后在堆内存中分配一块空间,将kitty猫的属性存放进去;(2)因为Cat有构造函数,我们在new时会在栈内存中定义_weight,_age并赋值(3.0,2),同时在堆中开辟空间,通过构造函数将栈内存中的值附给堆内存中值;(3)最后让引用变量指向这个空间,over。
总结:
栈中用来存放一些原始数据类型的局部变量数据和对象的引用(String,数组.对象等等)但不存放对象内容;堆中存放使用new关键字创建的对象.
字符串是一个特殊包装类,其引用是存放在栈里的,而对象内容必须根据创建方式不同定(常量池和堆).有的是编译期就已经创建好,存放在字符串常量池中,而有的是运行时才被创建.使用new关键字,存放在堆中。
静态成员变量在类装载的时候就进行了创建,在整个程序结束时按序销毁。实例变量在类实例化对象时候创建,在对象销毁的时候销毁。局部变量在局部范围使用时创建,跳出局部范围销毁。
不足之处,敬请指正,thank you~~~