栈与堆是Java
在Ram
中存放数据的地方,由Java
自动管理,不能直接设置。
堆 heap##
是一个运行时数据区,类的对象从中分配空间。由垃圾回收器管理。
对象:
通过new、newarray、anewarray、multianewarray
等指令建立,不需程序代码来显式的释放。
JDK 5.0
前,Integer i = 3;
表达式是不被允许的,因为类与字面值不能通用,除String
。
JDK 5.0
后,可以这么写,编译器在后台进行Integer i = new Integer(3);
转换。
优点#####
1、动态地分配内存大小;
2、生存期不必事先告诉编译器。因为是在运行时动态分配内存,垃圾回收器会自动回收不再使用的数据。
缺点#####
由于在运行时动态分配内存,存取速度较慢。
栈 stack##
是一个先进后出的数据结构,存放基本类型的变量和对象的引用变量(类实例)。
基本类型(primitive types)
共8种:int, short, long, byte, float, double, boolean, char
(无string基本类型)。
自动变量
基本类型通过诸如int a = 3;
的形式来定义,称为自动变量。
自动变量存的是字面值,非类的实例(不是类的引用,也没有类存在)。a
是一个指向int
类型的引用,指向3
这个字面值。
字面值的数据,由于大小可知,生存期可知(固定定义在某个程序块里面,程序块退出则字面值消失),故存在栈中。
优点#####
1、存取速度比堆要快,仅次于寄存器;
2、数据可以共享。
缺点#####
存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。
数据共享#####
int a = 3;
int b = 3;
编译器先处理int a = 3;
1、在栈中创建一个变量为a
的引用;
2、查找栈中是否有3
这个值,若没有,则将3
存进栈中,将a
指向3
。
接着处理int b = 3;
3、在栈中创建一个变量为b
的引用;
4、查找栈中是否有3
这个值,因栈中已有,则将b
直接指向3
。
5、此时,令a = 4;
编译器会搜索栈中是否有4
值,若没有,则将4
存进栈中,将a
指向4
;若有,直接将a
指向4
。
因此a
值的改变不会影响到b
值,由编译器完成,有利于节省空间。
总结###
基本类型变量:只在栈内存占用内存,保存对应的值,
引用类型变量:在栈内存保存的是一个指向堆内存的地址,通过这个地址,可以找到实例在堆区对应的对象。在在栈内存和堆内存都占用内存。Class c= new Class();
定义变量(实例)c
,new Class()
创建Class
对象。实例在栈中,对象在堆中,操作实例是通过实例的指针间接操作对象。多个实例可以指向同一对象。栈和堆中的数据销毁并非同步。方法结束,栈中的局部变量立即销毁,但是堆中对象不一定销毁。因为可能有其他变量也指向该对象,直到栈中没有变量指向堆中的对象时,它才销毁,而且还不是马上销毁,要等垃圾回收扫描时才会被销毁。
==、equals##
==
比较的是值【变量(栈)内存中存放的对象的(堆)内存地址】
equals
1、非包装类数据:等同于==
2、包装类数据:比较两个对象的值是否相同【堆内存中的内容】
==
比equal
运行速度快,因为"=="只是比较引用。
包装类数据
如Integer、String、Double
等将相应的基本数据类型包装起来的类。这些类数据存放在堆中
源码#####
Object
类中的equals
方法和==
一样,引用数据类型重写了equals
方法。
//Object类中equals方法
public boolean equals(Object obj) {
return (this == obj);
}
//String类重写的equals方法
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String) anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
String 类#####
String
类由final
修饰,不能被继承,是不可变类。
对象创建完成后,正常情况下,对象的状态不会因外界的改变而改变(对象的状态指对象的属性,包括属性的类型及属性值)。
String str = "abc";
System.out.println(str); // abc
str = "def";
System.out.println(str); // def
str
是存储在栈内存中指向堆内存中的引用,即存储的是对象在堆中的地址,而非对象本身。
此时堆内存中依然存在abc
、def
对象。对于abc
对象本身而言,对象的状态没有发生任何变化。
String
是一个特殊的包装类数据。
//两种创建方式
(1)String str = new String("abc");
(2)String str = "abc";
第一种:用new()
创建的对象存放在堆中。每调用一次便创建一个新的对象。
第二种:先在栈中创建String
类的对象引用变量str
,并在堆中创建对象abc
。
//示例
String str1 = new String ("abc");
String str2 = new String ("abc");
System.out.println(str1==str2); // false
System.out.println(str1.equals(str2)); //true
//str1、str2分别创建了一个abc对象
String str1 = "abc";
String str2 = "abc";
System.out.println(str1==str2); //true
System.out.println(str1.equals(str2)); //true
//abc对象只在创建str1时创建,创建str2时并未创建新的abc对象,但指向str1创建的abc
String str1 = new String("abc");
String str2 = "abc";
System.out.println(str1==str2); //false
System.out.println(str1.equals(str2)); //true
//str1、str2分别创建了一个abc对象