• java反射机制


    反射

    反射被称为框架设计的灵魂

    1568517281277
    JAVA运行的三个阶段:

    1568517527821

    1. .java文件通过javac编译为.class字节码文件,这些都是存放在硬盘中的,这个阶段称为源代码阶段
    2. ClassLoader将字节码文件加载到内存
    3. class是一个用来描述字节码文件的类。其的成员变量、构造方法和成员方法分别被封装为Field[]、Constructor[]、Method[]对象(因为可能有多个,所以用数组进行描述)。--这就是一个反射的过程

    例如,当我们在IDE中定义了一个对象后,IDE会将这个对象对应的类的字节码文件加载到内存中,对应的class对象将其所有的成员方法封装为Method[],这样只需要将Method[]中的元素变量显示出来,就达到了代码提示的效果

    反射的好处:

    1568518178168

    获取字节码文件Class对象

    1568519847034
    第一种方式:字节码文件未加载进内存时

    第二种:字节码文件已加载到内存中

    第三种:已经在运行、有对象了

    1568519762769
    举一个例子:

    Demo1.java

    import domain.Person;
    
    /*
    *@author JiaDing
    */
    public class Demo1 {
    /*
     * 获取Class的三种方式
     */
    	public static void main(String[]args) throws Exception {
    		//1.Claa.forName("全类名")
    		Class cls1=Class.forName("domain.Person");
    		System.out.println(cls1);
    		//2.类名.class
    		Class cls2=Person.class;
    		System.out.println(cls2);
    		//3.对象.getClass()
    		Person p=new Person();
    		Class cls3=p.getClass();
    		System.out.println(cls3);
    	}
    }
    
    

    Person.java

    package domain;
    /*
    *@author JiaDing
    */
    public class Person {
    	private String name;
    	private int age;
    	public String getName() {
    		return name;
    	}
    	public void setName(String name) {
    		this.name = name;
    	}
    	public int getAge() {
    		return age;
    	}
    	public void setAge(int age) {
    		this.age = age;
    	}
    	public Person() {
    		
    	}
    	public Person(String name,int age) {
    		this.name=name;
    		this.age=age;
    	}
    	@Override
    	public String toString() {
    		return "Person [name=" + name + ", age=" + age + "]";
    	}
    	
    }
    
    

    1568519931458

    使用Class对象

    1568520486913

    1. 获取成员变量

    getFields()获取的所有public成员变量!,而getDeclaredFields()获取的才是所有的成员变量(输出时会输出权限修饰符)!

    getDeclaredFields()可以突破private限制对私有变量进行读写!

    1568530697598
    在使用前需要忽略访问权限修饰符的安全检查:暴力反射!

    对成员变量能做的两个操作:设置值void set(Object obj,Object value)、获取值get(Object obj)

    1568530107861
    2. 获取构造方法

    获取时要给出不同参数类型的类

    1568530993796
    有了构造方法获得的构造器,就可以用来创建对象了

    1568531120435
    如果构造使用空参数构造方法创建对象,则可以简化为用class对象中专用的newInstance方法

    1568531281541
    要访问私有构造方法时:

    constructor1.setAccessible(true)

    关于setAccessible()方法,可以看这篇文章:https://www.cnblogs.com/ixenos/p/5699420.html

    这里抽取原博客的一个例子,很好地体现了这个方法的作用:

    class Employee{
        private int id;
        private String name;
        private int age;
        
        public Employee(){
        
        }
        public Employee(int id, String name, int age){
            this.id = id;
            this.name = name;
            this.age = age;
        }
    
        private void setId(int id){
           this.id = id;
        }
        private int judge(int id){
            return this.id - id;
        }
        private String sayHalo(String name){
            return "Halo" + name;
        }
    }
    
    public class PrivateTest{
         public static void main(String[] args){
             Employee em = new Employee(1, "Alex", 22);
            //获取Class对象
             Class<?> emClass =  em.getClass();
     
             //获取特定的声明了的方法
             Method judgeMethod = emClass.getDeclaredMethod("judge", new Class[]{Integer.TYPE});
             //setAccessible(boolean flag)使所有成员可以访问,访问之前设置
             judgeMethod.setAccessible(true);
     
             //获取所有声明的方法
             Method[] allMethods = emClass.getDeclaredMethods();
             //AccessibleObject.setAccessible(AccessibleObject[] array,
                                      boolean flag)批量给访问权限
             AccessibleObject.setAccessible(allMethods, true);
     
             //下面就可以通过反射访问了
             judgeMethod.invoke(em, new Object[]{3});
     
             //or...
             for(Method method : allMethods){
              ...
             }
         }
    }
    
    1. 获取成员方法

    Method对象调用对应的方法:invoke(Object obj,Object ··· args)//传入一个对象和执行该参数需要的参数

    通过getMethods()获取的方法不仅有该类我们定义的方法,还有继承自Object类的方法

    开启暴力反射:method.setAccessible(true);

    获取该方法的名称:String getName();

    String name=method.getName();

    1. 获取类名

    1568531876181
    这样获取的类名是全类名

    反射案例

    1568532864248
    前提:不能改变该类的任何代码,即创建一种通用的方法

    1568533707867
    配置文件类型:.properties,在其中使用全类名(换句话说,如果我们看到一个配置文件中使用的是全类名,我们也可以猜测它使用了反射原理)

    1568534174160
    1568533943763
    利用类加载器的方法获取配置文件资源

    1568534011047
    1568534055038
    这样每次只需要修改配置文件就好了。相比于修改代码,修改配置文件不需要重新编译、测试、上线,也提高了程序的拓展性。

  • 相关阅读:
    基于Dubbo的压测调优实例
    Rsync同步工具安装文档
    Codeforces 114A-Cifera(暴力)
    UVa 872
    Highcharts可拖动式图表
    Android中配置JDK和SDK的环境变量
    用CSS border相关属性画三角形
    屌丝程序猿赚钱之道 之APP
    软件开发工具(一)——概论
    建造者模式(屌丝专用)
  • 原文地址:https://www.cnblogs.com/jiading/p/12357886.html
Copyright © 2020-2023  润新知