《Java内存分配》
Java内存分配和管理是Java的核心技术之一。涉及以下:栈、堆、常量池、静态域。
1. 常量池:constant pool。指在编译期被确定,并被保存在已编译的.class文件中的一些数据。是个有序集合,以表的形式。主要包括:
a) 用final定义的常量。可以是基本数据类型(int、long等),也可是对象型(数组等)。
b) 类、接口、字段、方法的名字和描述符。
注意的是,String作为特殊的类型,若初始化方式是String a = "abc",则"abc"是存于常量池中的,即String字符串是不可变的。而String a = new String("abc")则不同。
2. 静态域:存放在队形中用static定义的成员。
3. 栈:使用上特点是读取速度快,但是只能存定长的、不可变的数据。
当在一段代码块定义一个变量时,Java就在栈中为这个变量分配内存空间;当该变量退出该作用域后,Java会自动释放掉为该变量所分配的内存空间,该内存空间立即被另作他用。主要包括:
a) 基本数据类型的变量及其数据。
eg:int a = 9。a和9都存在栈中,并且a指向9。注意,当同时有int b = 9时,则只存入b并指向9;当a的值改变,如下面有a = 10,则存入10并让a指向10。基本数据变量的这种储存方式,与引用变量完全不同。
b) 引用数据类型(即,对象)的引用变量。
引用变量是一个内存地址(Java指针),指向该对象在堆中储存的数据的首地址。
4. 堆:用来存放new出来的对象和数组。
引用变量在程序运行到其该作用域之外时,Java会自动释放掉栈中的引用变量;注意,堆中的数据不会立即被释放;在堆中分配的内存,由GC(JVM垃圾自动回收器)来不定期回收。
5. String的存储方式:String包装类比较特殊,跟基本数据类型和对象的存储方式都不同,而且初始化方式、“+”连接运算符等会有特殊的处理方式。
初始化时,其引用存于栈,但是数据可能存放在常量池中(编译时就已创建好),有的存放在堆中(运行时才被创建)。
eg:String a = "hello";
String b = "hello";
System.out.println(a == b); //true
上例,这种初始化方式,"hello"存放于常量池中,a和b都指向它。
eg:String a = new String("hello");
String b = new String ("hello");
System.out.println(a == b); //false
System.out.println(a.equals(b)); //true
上例,两次初始化new了两个对象,堆中没有常量池或栈的那种机制,不会判断两次new的对象的数据是否相等,所以是false。
注意:a.equals(b)取决于是否重写了equals方法,Object类的默认equals()方法比较的就是a == b;String重写了equals方法。
6. 值传递和引用传递:跟上述内存分配机制密切相关,总结为:
a. 值传递(传递的是拷贝):基本数据类型 和 String的直接复制情况。(即常量池)
b. 引用传递(传递的是引用&指针&内存地址):引用数据类型。