java类加载器和反射机制
类加载器
- 负责将.class文件加载到内在中,并为之生成对应的Class对象。
类加载器的组成
- Bootstrap ClassLoader 根类加载器
- Extension ClassLoader 扩展类加载器
- Sysetm ClassLoader 系统类加载器
类加载器的作用
- Bootstrap ClassLoader 根类加载器
- 也被称为引导类加载器,负责Java核心类的加载比如System,String等。在JDK中JRE的lib目录下rt.jar文件中
- Extension ClassLoader 扩展类加载器
- 负责JRE的扩展目录中jar包的加载。在JDK中JRE的lib目录下ext目录
- Sysetm ClassLoader 系统类加载器
- 负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径
反射机制
- JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
反射的一些常用方法:
创建对象
newInstance()
获取构造方法
getConstructors
getDeclaredConstructors
获取所有成员
getFields,getDeclaredFields
获取单个成员
getField,getDeclaredField
修改成员的值
set(Object obj,Object value)
获取所有方法
getMethods
getDeclaredMethods
获取单个方法
getMethod
getDeclaredMethod
暴力访问(private修饰)
method.setAccessible(true);
但想要这样使用,首必须得到class文件对象,就是得到Class类的对象,而得到Class类的对象有几种方式:
// 方式1(基本不用)
Person p = new Person();
Class c = p.getClass();
// 方式2(实际开发不怎么用)
Class c3 = Person.class;
// 方式3是通过字符串加载,而不是一个具体的类名。这样可以把字符串配置到配置文件中(比如:要求一个APP支持微信支付,支付宝支付,银联支付,以后甚至更多的支付方式,这样可以通过一个接口定义支付过程的几种状态,通过反射机制和面向对象的特性把配置文件配置此接口的实现类,以达到不修改任何代码下更换支付方式)
Class c4 = Class.forName(“cn.itcast_01.Person”);
反射获取成员变量并赋值
public class ReflectDemo {
public static void main(String[] args) throws Exception {
// 获取字节码文件对象
Class c = Class.forName("cn.itcast_01.Person");
// 获取所有的成员变量
// Field[] fields = c.getFields();
// Field[] fields = c.getDeclaredFields();
// for (Field field : fields) {
// System.out.println(field);
// }
/*
* Person p = new Person(); p.address = "北京"; System.out.println(p);
*/
// 通过无参构造方法创建对象
Constructor con = c.getConstructor();
Object obj = con.newInstance();
System.out.println(obj);
// 获取单个的成员变量
// 获取address并对其赋值
Field addressField = c.getField("address");
// public void set(Object obj,Object value)
// 将指定对象变量上此 Field 对象表示的字段设置为指定的新值。
addressField.set(obj, "北京"); // 给obj对象的addressField字段设置值为"北京"
System.out.println(obj);
// 获取name并对其赋值
// NoSuchFieldException
Field nameField = c.getDeclaredField("name");
// IllegalAccessException
nameField.setAccessible(true);// 值为true则指示反射的对象在使用时应该取消Java语言访问检查。
nameField.set(obj, "李四");
System.out.println(obj);
// 获取age并对其赋值
Field ageField = c.getDeclaredField("age");
ageField.setAccessible(true);
ageField.set(obj, 27);
System.out.println(obj);
}
}
反射获取成员方法并赋值
public class ReflectDemo {
public static void main(String[] args) throws Exception {
// 获取字节码文件对象
Class c = Class.forName("cn.itcast_01.Person");
// 获取所有的方法
// Method[] methods = c.getMethods(); // 获取自己的包括父亲的公共方法
// Method[] methods = c.getDeclaredMethods(); // 获取自己的所有的方法
// for (Method method : methods) {
// System.out.println(method);
// }
Constructor con = c.getConstructor();
Object obj = con.newInstance();
/*
* Person p = new Person(); p.show();
*/
// 获取单个方法并使用
// public void show()
// public Method getMethod(String name,Class<?>... parameterTypes)
// 第一个参数表示的方法名,第二个参数表示的是方法的参数的class类型
Method m1 = c.getMethod("show");
// obj.m1(); // 错误
// public Object invoke(Object obj,Object... args)
// 返回值是Object接收,第一个参数表示对象是谁,第二参数表示调用该方法的实际参数
m1.invoke(obj); // 调用obj对象的m1方法
System.out.println("----------");
// public void method(String s)
Method m2 = c.getMethod("method", String.class);
m2.invoke(obj, "hello");
System.out.println("----------");
// public String getString(String s, int i)
Method m3 = c.getMethod("getString", String.class, int.class);
Object objString = m3.invoke(obj, "hello", 100);
System.out.println(objString);
// String s = (String)m3.invoke(obj, "hello",100);
// System.out.println(s);
System.out.println("----------");
// private void function()
Method m4 = c.getDeclaredMethod("function");
m4.setAccessible(true);
m4.invoke(obj);
}
}
ArrayList的一个对象,在这个集合中添加一个字符串数据:
public class ArrayListDemo {
public static void main(String[] args) throws NoSuchMethodException,
SecurityException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
// 创建集合对象
ArrayList<Integer> array = new ArrayList<Integer>();
// array.add("hello");
// array.add(10);
Class c = array.getClass(); // 集合ArrayList的class文件对象
Method m = c.getMethod("add", Object.class);
m.invoke(array, "hello"); // 调用array的add方法,传入的值是hello
m.invoke(array, "world");
m.invoke(array, "java");
System.out.println(array);
}
}
总结:
通过反射可以修改java底层代码以达到我们所需要的功能,当然还有更深入知识需要去了解,去研究。