Java内存管理与反射机制
2017-03-26 21:51
253 查看
Java内存管理
理解Java程序运行时的内存管理,对很多相关技术的学习都有帮助,如Java的反射机制。Java是纯面对对象语言,没有C/C++“全局变量”的概念,只有“成员变量”与“局部变量”的概念,所有的变量都存在于一个类中。
先看一段代码:
package com.kwws.demo.reflect; public class A { public static final String TAG = "A"; private int id; public void setId(int newId) { this.id = newId; System.out.println(TAG + ".id=" + this.id); } public static void main(String[] args) { String tag = A.TAG;//line 1 A a = new A();//line 2 a.setId(99);// line3 } }
内存分配
Java程序运行时,涉及4块内存分配:栈内存(stack)、堆内存(heap)、代码段(code segment)、数据段(data segment),可以用下图表示:
栈内存(stack):存放局部变量的值:基础类型的值(
int a=1;中a的值为1)与引用类型的地址(
A a = new A();中a的值为内存地址0x0F2532,此时a称为A类对象的引用)
堆内存(heap):存放引用类型的对象的每个成员变量(如A类对象中的成员变量id),注意,不存放成员方法(如setId())。因此,创建一个引用类型的局部变量,在栈内存与堆内存各占用一块内存。
代码段(code segment):存放源程序代码,如类的成员方法(setId())和静态方法。注意,同一个类的不同对象共享该类的方法,并不是每创建一个对象就把成员方法复制一次。并且,对象使用方法时方法才被压入栈,不使用不占用内存。
数据段(data segment):存放静态变量和常量(和字符串常量)
main函数运行过程
1. line 1
String tag = A.TAG;:数据段(data segment)一段内存保存常量
TAG="A";栈内存(stack)存放局部变量tag,内容为指向数据段中
TAG="A"常量的存放地址(String为引用类型)
2. line 2
A a = new A();:堆内存(heap)开辟了一块空间给A的一个对象,该对象中包含一段内存保存成员变量id(
new A())。栈内存(stack)中保存新局部变量a,内容为堆内存中A对象的地址(
A a = ...),称“a是指向A的对象的引用”。
3. line 3
a.setId(99);:栈内存保存基本类型int的值99;代码段中载入setId代码,并对a调用了该方法,方法中的
this等于a,指向同一对象。
内存释放过程与垃圾回收
1. 修改a.id后,栈内存释放基本类型int 99的内存(立即出栈)
2. 栈内存中,局部变量a不被其他代码使用,a被释放(立即出栈)。此时,堆内存中A的对象不再被任何局部变量引用,GC随时可以回收该块堆内存(看GC心情)。
3. 局部变量tag不再使用,立即出栈。
4. 方法调用结束后,数据段与代码段内存中的内容被清空。
栈内存与堆内存在垃圾回收时的区别
可以看出,栈内存中的变量一旦不使用则立即释放占用的内存;而堆内存中的变量只有在不被任何变量引用时,垃圾收集器才会“看心情”回收这块内存。
Java反射机制
概念:Java的反射机制是在编译时并不确定哪个类被加载,而是在程序运行的时候才确定。Java反射允许在程序运行过程中通过API来取得已知class类的相关信息,可以动态地生成此类,并调用其方法或修改其成员变量(甚至是声明为private的方法或变量)。
作用:
将要使用的类A.class未编写完时,或者说开发初期不知道某个功能的具体实现时,可以使用反射,到程序运行期间(开发完成后)动态加载A.class。如支持扩展插件的程序。
在Android开发中,可以使用Java反射机制使用被@hide标记隐藏起来的API。
使用:
上文A.class中的main方法,可以等价替换为如下代码:
import java.lang.reflect.Method;//引入反射包 public static void main(String[] args) { try { Class A = Class.forName("com.kwws.demo.reflect.A");//根据类名找到指定类A Object a = A.newInstance();//实例化A类的一个对象a Method setId = A.getMethod("setId", int.class);//找到A类的setId方法,参数为int类 setId.setAccessible(true);//令该方法可访问 setId.invoke(a, 99);//对a调用setId方法,参数为99 } catch (Exception e) { e.printStackTrace(); } }
上述反射机制的使用,对应了Java内存管理的两点:
方法查找
Method setId = A.getMethod("setId", int.class);说明了:Java的成员方法是针对类级别A而言,而非对象a;
setId.invoke(a, 99);将A的对象a作为参数传入该方法,说明类的方法在内存中只拷贝一份,而不是每个对象一份。
通过Class类对象的getMethod/getField方法可以获得类中包含private修饰在内的所有成员,由此可实现对private成员、@hide隐藏成员的访问。
参考
Java内存分配全面浅析Java反射机制的学习(概念、相关API)
Java(Android)反射机制实例(实践代码)
相关文章推荐
- 反射机制 java实现
- JAVA中的反射机制详解
- JAVA高新技术反射机制的原理之构造函数、普通方法和字段
- 浅谈Java中的反射机制
- (三)JAVA利用反射机制将XML中的内容放入实体对象中
- JAVA 反射机制剖析
- JAVA中利用反射机制进行对象和Map相互转换的方法
- [Java]反射机制及构造对象
- Java中的Array用法(反射机制)
- Deep learning about Java--贯穿Java的反射机制(1)
- Java通过反射机制使用非默认构造器创建对象
- Java的反射机制
- java 反射机制
- JAVA中的向下转型(downcasting)及泛型与向上转型(upcasting)及RTTI、反射机制
- Java中反射机制详解
- 这杯咖啡有毒( ? ) -- Java 的反射机制
- JAVA基础--JAVA中的反射机制详解
- 你需要理解的 Java 反射机制知识总结
- 通过java类的反射机制获取类的属性类型
- 初学者学Java(二十一)-------反射机制