我的技术学习物语果然有问题
(最后更新 )

反射

反射是十分重要的,是Java框架的灵魂

反射

  • 反射指的是可以在运行时加载,使用编译期间完全未知的类

  • 程序在运行中。可以动态加载一个只有名称的类。对于任意一个已加载的类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性

  • 一个类只有一个Class对象,在加载一次出来的Class对象也是之前的那一个

  • 加载完类之后,在堆内存里就会产生一个Class对象,类的整个结构信息会放到对应的Class对象中

获取Class对象的三种方式:

public class ReflectionTest {
    public static void main(String[] args)  {
//      1.用Class.forName()获取Class对象,推荐使用这个
        try {
            Class clazz1 = Class.forName("gui.beantest");//Class.forName(包名+类名)
            System.out.println(clazz1);
        } 
        catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

//      2.用 .class 来获取Class对象
        Class clazz2 = beantest.class;	//类名.class
        System.out.println(clazz2);

//      3.用 getClass()来获取Class对象
        beantest cc = new beantest(1,2,"name");
        Class clazz3 =  cc.getClass();		//对象.getClass()
        System.out.println(clazz3);

    }
}

获取类的信息

@SuppressWarnings("all")
public class ReflectionTest {
    public static void main(String[] args)  throws Exception {
        String path = "gui.beantest";
            Class clazz = Class.forName(path);
            System.out.println(clazz);


//            获取类的名字
        System.out.println(clazz.getName());            //包名+类名
        System.out.println(clazz.getSimpleName());      //类名

//            获取属性信息
        Field[] files1 = clazz.getFields();         //只能获得public类型的属性
        Field[] files2 = clazz.getDeclaredFields();//能获得所有类型的属性
        Field f =clazz.getDeclaredField("uname");//获得这个属性的
            System.out.println(files1.length);
            System.out.println(files2.length);
            System.out.println(f);

//            获取方法信息
        Method[] method1 = clazz.getMethods();   //只能获得public类型的方法
        Method[] method2 = clazz.getDeclaredMethods();   //获得所有类型的方法
        Method m = clazz.getMethod("setId",int.class);    //获取这个方法,没参数就写null,有参数就传参数类型的class
            System.out.println(method1.length);
            System.out.println(method2.length);
            System.out.println(m);

//          获取构造器信息
        Constructor[] constructors = clazz.getDeclaredConstructors();
        Constructor c =clazz.getDeclaredConstructor(int.class,int.class,String.class);    //传递不同的参数类型获取不同的构造器
        for(Constructor temp:constructors){
            System.out.println(temp);
        }
        System.out.println(c);
    }
}

动态操作

public class Demo01 {
    public static void main(String[] args) throws Exception{
        Class clazz = Class.forName("test.Bean");
        
//        通过反射调用构造方法,构造对象
        Bean u1 = (Bean) clazz.getDeclaredConstructor().newInstance();
        System.out.println(u1);
        Bean u2 = (Bean) clazz.getDeclaredConstructor(int.class,int.class,String.class).newInstance(1,2,"ee");
        System.out.println(u2.getUname());
        
//        通过反射调用普通方法
        Bean u3 =(Bean) clazz.getDeclaredConstructor().newInstance();
        Method me = clazz.getMethod("setId", int.class);
        me.invoke(u3,5);		//通过Method的invoke方法来使用方法
        System.out.println(u3.getId());
        
//        通过反射操作属性
        Bean u4 =(Bean) clazz.getDeclaredConstructor().newInstance();
        Field f = clazz.getDeclaredField("uname");
        f.setAccessible(true);//这个属性不需要安全检查,可以直接访问,不然私有的属性不能修改
        f.set(u4,"lll");
        System.out.println(u4.getUname());
        System.out.println(f.get(u4));
        
    }
}

getDeclaredConstructor()这个方法会查找到所有的构造方法,然后通过后面的newInstance()方法来完成实例化,在强转就可以得到类了。如果有参数就输入参数。(注意这个Javabean中最好要有一个无参构造器,不然无参的这个实例化会报错)

反射机制的性能问题

  • setAccessible(),启用和禁用安全检查的开关,true时取消Java访问检查,但并不是true就能访问,false就不能访问

  • 禁止安全检查可以提高反射的运行速度

    public class Demo02 {
        public static void main(String[] args) throws Exception{
            test01();
            test02();
            test03();
        }
        public static void test01(){
            Bean u = new Bean();
            long start = System.currentTimeMillis();
            for(int i = 0;i<1000000000L;i++){
                u.getUname();
            }
            long end = System.currentTimeMillis();
            System.out.println("调用普通方法耗时为:"+(end-start)+"ms");
        }
    
        public static void test02() throws Exception{
            Bean u = new Bean();
            Class clazz = u.getClass();
            Method me = clazz.getDeclaredMethod("getUname",null);
            long start = System.currentTimeMillis();
            for(int i = 0;i<1000000000L;i++){
                me.invoke(u, null);
            }
            long end = System.currentTimeMillis();
            System.out.println("运用反射调用方法耗时为:"+(end-start)+"ms");
        }
    
        public static void test03() throws Exception{
            Bean u = new Bean();
            Class clazz = u.getClass();
            Method me = clazz.getDeclaredMethod("getUname",null);
            me.setAccessible(true);
            long start = System.currentTimeMillis();
            for(int i = 0;i<1000000000L;i++){
                me.invoke(u, null);
            }
            long end = System.currentTimeMillis();
            System.out.println("关闭访问检查后运用反射调用方法耗时为:"+(end-start)+"ms");
        }
    
    }

    这里就可以知道,运用反射调用方法的时间差不多是直接调用方法的时间的10倍,而关闭了访问检查之后就下降到接近5倍的程度