java基础(四)

来源:互联网 发布:java md5 32加密算法 编辑:程序博客网 时间:2024/05/16 06:00

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底层代码以达到我们所需要的功能,当然还有更深入知识需要去了解,去研究。

0 0