java类的加载机制和反射浅析
来源:互联网 发布:手机在线客服系统源码 编辑:程序博客网 时间:2024/06/01 10:08
原文请参考(感谢作者):http://blog.hesey.net/2011/04/introduction-to-java-virtual-machine.html
上面简单的描述了类的加载机制。下面继续介绍类的加载、反射、动态代理。
一、 类的加载
当程序加载某个类时,如果该类还并未加载到内存中,则系统会通过加载、连接、初始化3步来实现对这个类进行初始化。
- 加载
- 指将class文件读入内存,并为之创建一个Class对象;
- 任何类被使用时系统都会为之创建一个Class对象。(这个Class就是用来表示.class文件内容的)
- 连接
- 验证 是否有正确的内部结构,并和其他类协调一致
- 准备 负责为类的静态成员分配内存,并设置默认初始化值
- 解析 将类的二进制数据中的符号引用替换为直接引用
- 初始化
1、类初始化的时机
- 创建类的实例
- 访问类的静态变量,或者为静态变量赋值
- 调用类的静态方法
- 使用Java反射机制来强制创建某个类或接口对应的java.lang.Class对象
- 初始化某个类的子类
- 直接使用java.exe命令来运行某个主类
2、类加载器
类加载器:负责将.class文件加载到内存中,并为之生成对应的Class对象。
类加载器的组成:根类加载器、扩展类加载器、系统类加载器。(参考文章开始的图片)
二、反射
Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有的属性和方法;对于任意一个对象,都能够调用他的任意一个属性和方法;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。
要想解剖一个类必须要先获取到该类的字节码文件对象,而解剖使用的就是Class类中的方法,所以要先获取到每一个字节码文件对应的Class类型的对象。
1. 获取类的Class对象(有三种方式):
public class ReflectDemo { // 获取Class对象的方式 public static void main(String[] args) throws ClassNotFoundException { // 方式一: Person p = new Person(); Class cp = p.getClass(); System.out.println(cp); // Class对象class cn.qidd.Person Person p1 = new Person(); Class cp1 = p1.getClass(); System.out.println(p == p1); // false System.out.println(cp == cp1); // true 该class文件的Class对象只有一个 // 方式二: Class cp3 = Person.class; System.out.println(cp3 == cp); // true // 方式三: Class cp4 = Class.forName("cn.qidd.Person"); System.out.println(cp4 == cp); // true }}
以上的三种方式都可以获取到类的Class对象,但是一般开发时推荐使用的是第三种,因为参数是一个字符串,而不是一个具体的类名,在开发中这个字符串可以放在配置文件中。前面的2种方式,可以在平时练习时使用比较方便。
2. 通过Class对象获取它的成员
通过反射获取构造器
public class ReflectDemo1 {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException { Class c = Class.forName("cn.qidd.Person"); // 获取到它的所有构造方法 // 1-获取到所有公共构造方法,返回数组 Constructor[] constructors = c.getConstructors(); System.out.println(Arrays.toString(constructors)); // 2-获取到所有构造方法,返回数组 Constructor[] declaredConstructors = c.getDeclaredConstructors(); System.out.println(Arrays.toString(declaredConstructors)); // 3-获取到构造方法,返回构造器对象 // Constructor getConstructor(Class<?> ...parameterType) Constructor constructor = c.getConstructor(String.class,int.class); System.out.println(constructor);}}
- 通过反射获取构造方法并使用
public class ReflectDemo2 { public static void main(String[] args) throws Exception { Class c = Class.forName("cn.qidd.Person"); // 获取公有构造器(public) // 当使用此方法获取私有构造器时出现没有该方法的异常 Constructor constructor = c.getConstructor(String.class,int.class,String.class); // 创建对象 Object o = constructor.newInstance("孙艳平", 25, "陕西省"); System.out.println(o); // 获取私有构造器/公有构造器 Constructor con = c.getDeclaredConstructor(String.class); con.setAccessible(true); // 当不设置时非法异常,此处意思是指示使用Java反射的对象在使用时取消Java语言的访问权限 Object o1 = con.newInstance("孙艳平"); System.out.println(o1); }}
获取成员变量
public class ReflectDemo3 {public static void main(String[] args) throws Exception { Class c = Class.forName("cn.qidd.Person"); Field[] fields = c.getFields(); // 获取到所有公共成员变量 Field[] fields1 = c.getDeclaredFields(); // 获取到所有成员变量 Field f = c.getField("address"); // 获取某公共成员变量 Field f2 = c.getDeclaredField("name"); // 获取任意一个成员变量 Constructor constructor = c.getConstructor(); Object o = constructor.newInstance(); f2.setAccessible(true); f2.set(o, "孙艳平"); System.out.println(o);}}
- 获取成员方法
public class ReflectDemo4 { public static void main(String[] args) throws Exception { Class c = Class.forName("cn.qidd.Person"); // 获取所有公共的方法(将他的父类的公共的方法也拿到) Method[] methods = c.getMethods(); // 获取所有的方法(只有自己的),包含私有的 Method[] methods1 = c.getDeclaredMethods(); // 获取单个方法并使用(public) Constructor con = c.getConstructor(); Object o = con.newInstance(); Method method = c.getMethod("show"); method.setAccessible(true); Object invoke = method.invoke(o); // 调用o的show方法 // 获取单个方法(private修饰) Method m = c.getDeclaredMethod("function",String.class); m.setAccessible(true); Object o1 = m.invoke(o, "孙艳平"); System.out.println(o1); }}
3. 通过反射越过泛型检查
在此处先看一段代码:
public class ReflectDemo5 { public static void main(String[] args) throws Exception { ArrayList<Integer> arr = new ArrayList<Integer>(); arr.add(10); }}
编译之后的:
public class ReflectDemo5 { public ReflectDemo5() { } public static void main(String[] args) throws Exception { ArrayList arr = new ArrayList(); arr.add(Integer.valueOf(10)); }}
我们可以看见泛型在编译之后就不存在了,但是10变成Integer类型加到List中了。
对于那些泛型来说,实际上是Object类型。
使用反射直接操作Class对象,在Class对象中ArrrayList的add方法并没有泛型限制。
public class ReflectDemo5 { public static void main(String[] args) throws Exception { ArrayList<Integer> arr = new ArrayList<Integer>();// arr.add(10); // 使用反射获取ArrayList的add方法,并使用 Class c = arr.getClass(); Method addM = c.getMethod("add", Object.class); addM.setAccessible(true); // 调用后arr的add方法,存入“hello” addM.invoke(arr, "hello"); System.out.println(arr); }}
阅读全文
0 0
- java类的加载机制和反射浅析
- Java类加载机制和反射机制
- 浅析java的反射机制
- java 加载类和反射机制的总结
- Java中反射机制和类的加载过程
- Java类加载机制和反射
- 类的加载机制和反射总结
- 类的加载机制和反射
- java反射机制浅析和使用
- 深入理解java:类加载机制 和 反射机制
- Java类加载机制浅析
- 浅析Java反射机制
- Java 反射机制浅析
- Java 反射机制浅析
- Java 反射机制浅析
- Java 反射机制浅析
- Java 反射机制浅析
- 浅析java反射机制
- Kafka+storm+hbase<三者集成遇到坑以及解决办法>
- 1003. 我要通过!(20)
- Webbrowser知识点记录(c#研发)
- 线程辅助类(三)--Semaphore
- (七) Fiori经典布局介绍之Employee List
- java类的加载机制和反射浅析
- [INS-30131] 执行安装程序验证所需的初始设置失败.
- 常见排序算法(Java实现)
- id生成策略-(联合主键xml annotation)-5
- latex插入图片
- POJ 1583 Choose Your Words Carefully 笔记
- VPS搭建VPN
- python学习之路一
- Erlang语言精髓之一