Java 反射(Reflection)

604 查看

反射的核心就是Class对象,每一个类被jvm加载都会有一个对应的class对象,这个class对象包含了这个类的结构信息,反射就是会通过反射api反复操作这个class对象(属性,方法,注解,构造器,泛型),但是反射会降低程序的运行效率,比普通方法要慢30倍,通过setAccessble(true) 跳过安全检查(可以读取private 的属性),提高4倍的程序运行效率
反射将普遍运用到各个类型的框架。
效率:
1,运行效率:使用反射 减低程序的运行效率。
2,开发效率:由于反射运用到各个java框架中,大大加快了开发的效率。

下面就是一些简单的例子来具体阐述反射的一些特点:

 package com.mk;
     public class Test{
     public static void main(String [] args){
        Foo foo = new Foo();//foo 表示foo的实例对象
        //任何一个类都是class的实例对象,有3钟表达方式
        //1,任何一个类都有一个隐含的成员变量Class
        Class c1 = Foo.class;
        //2,通过getClass方法获得
        Class c2 = foo.getClass();
        //不管是c1还是c2都代表Foo类的类类型,一个类只能是Class的实例对象
        System.out.println(c1==c2);//true
        //3,第三种表达方式
        Class c3 = null;
        try {
            c3 = Class.forName("com.mk.Foo");//类的全称
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        System.out.println(c2==c3);//true

        //可以通过类的类类型创建该类的对象实例
        try {
            Foo f1 = (Foo) c1.newInstance();//需要无参数的构造方法
            f1.print();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
     }
    }
       class Foo{
        void print(){
        System.out.println("print parent");
       }
    }

动态加载类
new 创建对象 是静态的加载类,在编译的时刻就需要加载 所有可能使用到的类
通过动态的加载类可以解决这个问题
运行时刻加载 就是想用哪个就加载哪个,不用就不加载。
通过反射api 操作类的方法

method.invoke(对象,参数列表)
    package com.mk;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    public class Test1 {
    public static void main(String[]args) throws
      NoSuchMethodException,      
        InvocationTargetException,
     IllegalAccessException {
        A a1 = new A();
        Class c = a1.getClass();//得到类类型
        Method m = c.getMethod("print",int.class,int.class);
        //方法的反射操作
        //a1.print(10,20);方法的反射操作是用m对象进行方法的调用,和a1.print()的调用效果相同
        //方法如果没有返回值返回null,如果有返回值就返回具体的值
        //Object obj = m.invoke(a1,new Object[]{10,20});
        //或者有几个参数传几个参数
        Object ob = m.invoke(a1,10,20);
      }
     }
    class A{
    public void print(int a,int b){
        System.out.println(a+b);
      }
    }

通过class,method来认识泛型的本质

 package com.mk;
    java.lang.reflect.Method;
    java.util.ArrayList;
    class test2 {
    public static void main(String[] arg){
        ArrayList list = new ArrayList();
        ArrayList<String> ls = new ArrayList<String>();
        ls.add("hello");
        //ls.add(20);//泛型检查错误,20是加不进去的
        Class c1 = list.getClass();
        Class c2 = ls.getClass();
        System.out.println(c1==c2);//反射的操作都是编译之后的操作
        /**
         * c1==c2 结果返回true说明编译之后的集合的泛型是去泛型化的,java中
         * 集合的泛型,是防止错误输入的,只有在编译阶段是有效的,在其他的阶段都是
         * 无效的
         * 可以通过方法的反射来操作 绕过编译
         */
          try {
            Method m = c2.getMethod("add",Object.class);
            m.invoke(ls,100);
            System.out.println(ls.size());
            System.out.println(ls);//[hello, 100] 结果int 是可以加进去的
         } catch (Exception e) {
            e.printStackTrace();
        }

      }
    }

如何通过反射api 操作属性,构造器

public class User {
    private int id;
    private String name;
    //javabean 无参构造器,用于java的反射机制的初始化
    public User() {
        
    }
    public User(int id, String name) {
        super();
        this.id = id;
        this.name = name;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
        Class clazz 
             = Class.forName("com.test.reflection.Bean.User");
        //获取名字
        System.out.println(clazz.getName());//包名+类名
        System.out.println(clazz.getSimpleName());
        //获取属性方法(重载,根据参数找方法)
        Field [] fs = clazz.getDeclaredFields();
        System.out.println(fs.length);//获取所有的fields,不论public还是private
        Field [] field = clazz.getFields();//获取公共属性
        for(Field fields:fs){
            System.out.println("属性:"+fields);
        }
        //获取方法信息
        Method [] method 
             = clazz.getDeclaredMethods();//获取所有的方法
        Method m1 = 
                clazz.getDeclaredMethod("getName",null);
        for(Method m:method){
            System.out.println("方法:"+m);
        }
        //获取构造器
        Constructor c1 = clazz.getConstructor(null);
        System.out.println("无参构造器:"+c1);
        Constructor c2 = clazz.getConstructor(int.class,String.class);
        System.out.println("有参构造器:"+c2);
        Constructor [] constructors 
            = clazz.getDeclaredConstructors();
        for(Constructor c:constructors){
            System.out.println("构造器:"+c);
        }
        
        
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
}

 //动态操作构造器
      try {
        //通过反射api调用构造方法
        User user = (User) clazz.newInstance();//其实是调用了user的无参构造方法
        System.out.println(user);
        //调用有参构造器
        Constructor constructor 
            = clazz.getDeclaredConstructor(int.class,String.class);
        User u 
            = (User) constructor.newInstance(12,"michael");
        System.out.println(u.getName());
        //通过反射api调用普通的方法
        User u1 
             = (User)clazz.newInstance();
        Method method 
             = clazz.getDeclaredMethod("setName", String.class);
        method.invoke(u1, "mike");//setName("mike");
        System.out.println(u1.getName());
        //通过反射操作属性
        User u2 = (User) clazz.newInstance();
        Field  f 
             = clazz.getDeclaredField("name");//属性必须是public的
        f.setAccessible(true);//不需要安全检查,直接访问
        f.set(u2, "mike2");
        System.out.println(u2.getName());//通过反射直接读动态值
        System.out.println(f.get(u2));
    } catch (Exception e) {
        e.printStackTrace();
    }