JAVA : 反射机制

来源:互联网 发布:淘宝有货提醒 编辑:程序博客网 时间:2024/04/29 14:34

反射机制

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。

JAVA反射(放射)机制:“程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言”。从这个观点看,Perl,Python,Ruby是动态语言,C++,Java,C#不是动态语言。但是JAVA有着一个非常突出的动态相关机制:Reflection,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。


功能

java反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理。

它有着一个非常突出的动态相关机制:Reflection。这个字的意思是“反射、映象、倒影”,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。这种“看透class”的能力(the ability of the program to examine itself)被称为introspection(内省、内观、反省)。Reflection和introspection是常被并提的两个术语。


动态绑定

要想深入研究java的反射机制,首先要了解什么是动态绑定。动态是相对于静态来说的。二者的区别主要在于创建对象的时间不一同,静态绑定是编译时创建对象,而动态绑定是在运行时创建对象。

public class TestReflect  {    public static void main(String[] args) throws Exception {        String message = null;        ManPerson m1 = new ManPerson();        message = m1.eat("aaa");//静态方式调用        System.out.println(message);        Class<?> clazz = Class.forName("com.kblsoft.reflect.one.ManPerson");        ManPerson m2 = (ManPerson) clazz.newInstance();//动态方式创建对象调用        message = m2.eat("bbbb");        System.out.println(message);    }}interface Person{    public abstract String eat(String food);}class ManPerson implements Person{    @Override    public String eat(String food) {        return "man eat " + food;    }}

通过一个对象获得完整的包名和类名

public class TestReflect {    public static void main(String[] args) {        TestReflect testReflect = new TestReflect();        System.out.println(testReflect.getClass().getSimpleName());//类名        System.out.println(testReflect.getClass().getName());//包名+类名        //output:        //TestReflect        // com.kblsoft.reflect.one.TestReflect    }}

实例化Class类对象

public class TestReflect {    public static void main(String[] args) throws Exception {        Class<?> class1 = null;        Class<?> class2 = null;        Class<?> class3 = null;        class1 = Class.forName("com.kblsoft.reflect.one.TestReflect");   // 一般采用这种形式        class2 = new TestReflect().getClass();//可用下面这种代替        class3 = TestReflect.class;        System.out.println("类名称   " + class1.getName());        System.out.println("类名称   " + class2.getName());        System.out.println("类名称   " + class3.getName());        //output        //类名称   com.kblsoft.reflect.one.TestReflect        //类名称   com.kblsoft.reflect.one.TestReflect        //类名称   com.kblsoft.reflect.one.TestReflect    }}

获取某个类中的全部构造函数

public class TestReflect {    public static void main(String[] args) throws Exception {        Class<?> clazz = Class.forName("com.kblsoft.reflect.one.Student");        //第一种方法,实例化        Student student = (Student) clazz.newInstance();        student.setAge(24);        student.setName("black");        System.out.println(student.getAge() + "::" + student.getName());        //output     24::black        //第二种   获取所有构造函数,逐个分析        Constructor<?> cons[] = clazz.getConstructors();        for (Constructor<?> con : cons) {            Parameter[] paras = con.getParameters();            System.out.println(con);            for (Parameter para : paras) {                System.out.println(para.getType().getName());            }        }        //output        //  public com.kblsoft.reflect.one.Student(int,java.lang.String)        //  int        //  java.lang.String        //  public com.kblsoft.reflect.one.Student(java.lang.String)        //  java.lang.String        //  public com.kblsoft.reflect.one.Student()    }}class Student {    public int age;    public String name;    public Student() {    }    public Student(String name) {        this.name = name;    }    public Student(int age, String name) {        this.age = age;        this.name = name;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }}

获取某个类的全部属性

权限修饰符在这里有用

public class TestReflect extends Param {    private int iSelf = 0;    public static void main(String[] args) throws ClassNotFoundException {        Class<?> clazz = Class.forName("com.kblsoft.reflect.one.TestReflect");        System.out.println("===============本类属性:getDeclaredFields===============");        // 取得本类的全部属性        Field[] field = clazz.getDeclaredFields();        for (Field f : field) {            // 权限修饰符            int mo = f.getModifiers();            String priv = Modifier.toString(mo);            // 属性类型            Class<?> type = f.getType();            System.out.println(priv + " " + type.getName() + " " + f.getName() + ";");        }        System.out.println("==========实现的接口或者父类的属性:getFields==========");        // 取得实现的接口或者父类的属性        Field[] filed1 = clazz.getFields();        for (Field f : filed1) {            // 权限修饰符            int mo = f.getModifiers();            String priv = Modifier.toString(mo);            // 属性类型            Class<?> type = f.getType();            System.out.println(priv + " " + type.getName() + " " + f.getName() + ";");        }    }}

获取某个类的全部方法

public class TestReflect extends Param {    public static void main(String[] args) throws Exception {        Class<?> clazz = Class.forName("com.kblsoft.reflect.one.TestReflect");        Method[] methods = clazz.getMethods();//获取全部方法,然后循环信息        for (Method method : methods) {            Class<?> returnType = method.getReturnType();            Class<?> paras[] = method.getParameterTypes();            int temp = method.getModifiers();            //获取方法修饰符和名称            //output public static void  main            System.out.print(Modifier.toString(temp) + " ");            System.out.print(returnType.getName() + "  ");            System.out.print(method.getName() + " ");            //获取方法参数            for (Class<?> para : paras) {                System.out.print(para.getName());            }            //获取方法的异常            Class<?> exces[] = method.getExceptionTypes();            for (Class<?> exce : exces) {                System.out.println(exce.getName());            }            System.out.println();        }    }    public static void testMethod(String param1,int param2) {    }    public String testMethod2(){        return "SUCCESS";    }}

通过反射机制调用某个类的方法

public class TestReflect extends Param {    public static void main(String[] args) throws Exception {        Class<?> clazz = Class.forName("com.kblsoft.reflect.one.TestReflect");        Method method1 = clazz.getMethod("reflect1");        method1.invoke(clazz.newInstance());        Method method2 = clazz.getMethod("reflect2",int.class,String.class);        method2.invoke(clazz.newInstance(),22,"black");//invoke  反射        //output          //Java 反射机制 - 调用某个类的方法1.        //Java 反射机制 - 调用某个类的方法2.        //age -> 22. name -> black    }    public void reflect1() {        System.out.println("Java 反射机制 - 调用某个类的方法1.");    }    public void reflect2(int age, String name) {        System.out.println("Java 反射机制 - 调用某个类的方法2.");        System.out.println("age -> " + age + ". name -> " + name);    }}

通过反射机制操作某个类的属性

private String proprety = null;    public static void main(String[] args) throws Exception {        Class<?> clazz = Class.forName("com.kblsoft.reflect.one.TestReflect");        Object obj = clazz.newInstance();        // 可以直接对 private 的属性赋值        Field field = clazz.getDeclaredField("proprety");//获取指定的属性值        field.setAccessible(true);//设置是否允许访问,而不是修改原来的访问权限修饰词。        field.set(obj, "Java反射机制");//set值        System.out.println(field.get(obj));//get值    }

反射机制的动态代理

代理设计模式 : 定义:为其他对象提供一种代理以控制对这个对象的访问。
一个典型的动态代理创建对象过程可分为以下四个步骤:

1、通过实现InvocationHandler接口创建自己的调用处理器 IvocationHandler handler = new InvocationHandlerImpl(…);

2、通过为Proxy类指定ClassLoader对象和一组interface创建动态代理类
Class clazz = Proxy.getProxyClass(classLoader,new Class[]{…});

3、通过反射机制获取动态代理类的构造函数,其参数类型是调用处理器接口类型
Constructor constructor = clazz.getConstructor(new Class[]{InvocationHandler.class});

4、通过构造函数创建代理类实例,此时需将调用处理器对象作为参数被传入
Interface Proxy = (Interface)constructor.newInstance(new Object[] (handler));
为了简化对象创建过程,Proxy类中的newInstance方法封装了2~4,只需两步即可完成代理对象的创建。
生成的ProxySubject继承Proxy类实现Subject接口,实现的Subject的方法实际调用处理器的invoke方法,而invoke方法利用反射调用的是被代理对象的的方法(Object result=method.invoke(proxied,args))

public class TestReflect  {    public static void main(String[] args) throws Exception {        MyInvocationHandler demo = new MyInvocationHandler();        Person sub = (Person) demo.bind(new RealPerson());        String info = sub.eat("children");        System.out.println(info);    }}interface Person{    public String eat(String food);}class RealPerson implements Person{    @Override    public String eat(String food) {        return "eat " + food;    }}class MyInvocationHandler implements InvocationHandler{//定义一个InvocationHandler接口的子类    private Object obj = null;    public Object bind(Object obj){//具体的实现        this.obj = obj;        return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),this);//创建动态代理    }    @Override    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        return method.invoke(this.obj,args);//对接口的调用重定向为对代理的调用    }}

通过反射取得并修改数组的信息

Array的使用

public class TestReflect  {    public static void main(String[] args) throws Exception {        int[] temp = { 1, 2, 3, 4, 5 };        Class<?> demo = temp.getClass().getComponentType();        System.out.println("数组类型: " + demo.getName());        System.out.println("数组长度  " + Array.getLength(temp));        System.out.println("数组的第一个元素: " + Array.get(temp, 0));        Array.set(temp, 0, 100);        System.out.println("修改之后数组第一个元素为: " + Array.get(temp, 0));        //output        //数组类型: int        //数组长度  5        //数组的第一个元素: 1        //修改之后数组第一个元素为: 100    }}

通过反射机制修改数组的大小

public class TestReflect  {    public static void main(String[] args) throws Exception {        int[] temp = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };        int[] newTemp = (int[]) arrayInc(temp, 15);        print(newTemp);        String[] atr = { "a", "b", "c" };        String[] str1 = (String[]) arrayInc(atr, 8);        print(str1);        //output        //数组长度为: 15        //1 2 3 4 5 6 7 8 9 0 0 0 0 0 0         //数组长度为: 8        //a b c null null null null null     }    // 修改数组大小    public static Object arrayInc(Object obj, int len) {        Class<?> arr = obj.getClass().getComponentType();        Object newArr = Array.newInstance(arr, len);        int co = Array.getLength(obj);        System.arraycopy(obj, 0, newArr, 0, co);        return newArr;    }    // 打印    public static void print(Object obj) {        Class<?> c = obj.getClass();        if (!c.isArray()) {            return;        }        System.out.println("数组长度为: " + Array.getLength(obj));        for (int i = 0; i < Array.getLength(obj); i++) {            System.out.print(Array.get(obj, i) + " ");        }        System.out.println();    }}

将反射机制应用于工厂模式

//现在我们利用反射机制实现工厂模式,可以在不修改工厂类的情况下添加任意多个子类。//但是有一点仍然很麻烦,就是需要知道完整的包名和类名,这里可以使用properties配置文件来完成。public class TestReflect  {    public static void main(String[] args) throws Exception {        Person p = Factory.getInstance("com.kblsoft.reflect.one.ManPerson");//接口接收,创建的是子类        if (null != p) {            System.out.println(p.eat("children"));        }    }}interface Person{    public abstract String eat(String food);}class ManPerson implements Person{    @Override    public String eat(String food) {        return "man eat " + food;    }}class WomanPerson implements Person{    @Override    public String eat(String food) {        return "woman eat " + food;    }}class Factory {    public static Person getInstance(String className){        Person person = null;        try {            person = (Person) Class.forName(className).newInstance();        } catch (Exception e) {            e.printStackTrace();        }        return person;    }}

参考
1. http://www.cnbl/lzq198754/p/5780331.html
2. java编程思想

0 0