Java 七分钟学习之反射(reflection)机制


一、什么是Java的反射机制?

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

Java反射机制主要提供了以下功能:

  • 在运行时判断任意一个对象所属的类;
  • 在运行时构造任意一个类的对象;
  • 在运行时判断任意一个类所具有的成员变量和方法;
  • 在运行时调用任意一个对象的方法;生成动态代理。

二、Class类及其使用

Class类

  • Class 是一个类; 一个描述类的类.
  • 封装了描述方法的 Method,
  • 描述字段的 Filed,
  • 描述构造器的 Constructor 等属性.
    ####获取Class 对象的三种方法
    //(1)使用Class类的forName静态方法:
    Class<?> class1 = Class.forName("an.example.Person");
    
    //(3)调用某个对象的getClass()方法,比如:
    Class<?> class2 = person.getClass();
    
    //(2)直接获取某一个对象的class,比如:
    Class<?> class3 = Person.class;
    Alt text

    三、Java反射API

    反射API用来生成JVM中的类、接口或则对象的信息。
  • Class类:反射的核心类,可以获取类的属性,方法等信息。
  • Field类:Java.lang.reflec包中的类,表示类的成员变量,可以用来获取和设置类之中的属性值。
  • Method类: Java.lang.reflec包中的类,表示类的方法,它可以用来获取类中的方法信息或者执行方法。
  • Constructor类: Java.lang.reflec包中的类,表示类的构造方法。

    四、使用反射

    1.获取Class对象

    2.通过获取方法和属性信息

    3. 使用反射API来操作

    package an.mark.note.test;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    
    public class Test {
    
    	private static Object newInstance;
    
    	public static void main(String[] args) {
    		try {
    			// 1.获取Person类的Class对象
    			// 总共有三种方式可以使用
    			Class clazz = Class.forName("an.mark.note.test.Person");
    
    			// 获取Person类的所有方法
    			Method[] method = clazz.getDeclaredMethods();
    			for (Method m : method) {
    				System.out.println(m.toString());
    			}
    
    			// 获取Person类的所有成员属性
    			Field[] field = clazz.getDeclaredFields();
    			for (Field f : field) {
    				System.out.println(f.toString());
    			}
    
    			// 获取Person类的所有构造方法
    			Constructor[] constructor = clazz.getDeclaredConstructors();
    			for (Constructor c : constructor) {
    				System.out.println(c.toString());
    			}
    
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    		System.out.println("_____________________________________________________________");
    		System.out.println("创建对象");
    		geneDemo();
    		System.out.println("_____________________________________________________________");
    		System.out.println("反射字段");
    		reflectField();
    		System.out.println("_____________________________________________________________");
    		System.out.println("反射方法");
    		reflectMethod();
    	}
    
    	public static void geneDemo() {
    		try {
    			// 获取Person类的Class对象
    			Class<?> clazz = Class.forName("an.mark.note.test.Person");
    			/**
    			 * 第一种方法创建对象
    			 */
    			// 创建对象
    			Person p = (Person) clazz.newInstance();
    			// 设置属性
    			p.setName("张三");
    			p.setAge(18);
    			p.setGender("男");
    			System.out.println(p.toString());
    
    			/**
    			 * 第二种方法创建
    			 */
    			// 获取构造方法
    			Constructor c = clazz.getDeclaredConstructor(String.class, String.class, int.class);
    			// 创建对象并设置属性
    			Person p1 = (Person) c.newInstance("李四", "男", 20);
    			System.out.println(p1.toString());
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    
    	public static void reflectField() {
    		Class<?> classOne = Person.class;
    		try {
    			// 通过方法创建对象实例并为其设置属性
    			Person newP = (Person) classOne.newInstance();
    			newP.setName("张三");
    			newP.setAge(18);
    			newP.setGender("男");
    			// 通过反射获取指定的字段
    			Field field = classOne.getDeclaredField("name");
    			// 解除访问权限(因为name在这里是私有的
    			field.setAccessible(true);
    			// 获取字段的类型
    			Class<?> type = field.getType();
    			// 打印字段类型
    			System.out.println("字段类型:" + type);
    			// 传入某个对象 获得该字段的值
    			Object object = field.get(newP);
    			Object obj = field.get(newP);
    			if (type.equals(String.class)) {
    				String value = (String) obj;
    				System.out.println("当前的姓名:" + value);
    			}
    			// 赋值
    			field.set(newP, "赵四");
    			System.out.println("通过反射修改后的姓名:" + newP.getName());
    		} catch (Exception e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    	}
    
    	public static void reflectMethod() {
    
    		try {
    			//获取class类
    			Class<?> classOne = Person.class;
    			// 通过方法创建对象实例并为其设置属性
    			Person newP = (Person) classOne.newInstance();
    			newP.setName("张三");
    			newP.setAge(18);
    			newP.setGender("男");
    			System.out.println("before name:"+newP.getName());
    			//通过Class对象的方法获得Method对象
    			Method method = classOne.getMethod("setName",String.class);
    			//执行方法
    			method.invoke(newP, "赵四");
    			System.out.println("after name:"+newP.getName());
    		} catch (Exception e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    
    	}
    
    }
    执行结果
    public java.lang.String an.mark.note.test.Person.toString()
    public java.lang.String an.mark.note.test.Person.getName()
    public void an.mark.note.test.Person.setName(java.lang.String)
    public void an.mark.note.test.Person.setAge(int)
    public void an.mark.note.test.Person.setGender(java.lang.String)
    public int an.mark.note.test.Person.getAge()
    public java.lang.String an.mark.note.test.Person.getGender()
    private java.lang.String an.mark.note.test.Person.name
    private java.lang.String an.mark.note.test.Person.gender
    private int an.mark.note.test.Person.age
    public an.mark.note.test.Person()
    public an.mark.note.test.Person(java.lang.String,java.lang.String,int)
    _____________________________________________________________
    创建对象
    姓名:张三  性别:男  年龄:18
    姓名:李四  性别:男  年龄:20
    _____________________________________________________________
    反射字段
    字段类型:class java.lang.String
    当前的姓名:张三
    通过反射修改后的姓名:赵四
    _____________________________________________________________
    反射方法
    before name:张三
    after name:赵四

    五、反射的好处

  • 反射(Reflection)是Java 程序开发语言的特征之一,它允许运行中的 Java 程序获取自身的信息,并且可以操作类或对象的内部属性。
  • 在不改变程序源代码的情况下,为程序添加特定的功能。如 :通过修改配置文件,使用forName(“xxxx”),用同一个标准实现,却可以添加特定的功能,反射最重要的用途就是开发各种通用框架。
  • 简而言之,通过反射,我们可以在运行时获得程序或程序集中每一个类型的成员和成员的信息。
  • 程序中一般的对象的类型都是在编译期就确定下来的,而Java反射机制可以动态地创建对象并调用其属性,这样的对象的类型在编译期是未知的。所以我们可以通过反射机制直接创建对象,即使这个对象的类型在编译期是未知的。
    *

Java反射框架主要提供以下功能:

  • 1.在运行时判断任意一个对象所属的类;
  • 2.在运行时构造任意一个类的对象;
  • 3.在运行时判断任意一个类所具有的成员变量和方法(通过反射甚至可以调用private方法);
  • 4.在运行时调用任意一个对象的方法

    六、注意事项

  • 反射会额外消耗一定的系统资源,如果不需要动态地创建一个对象,那么就不需要用反射。
  • 反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题。
    ###七、反射和JVM
    在java里面任何class都要装载在虚拟机上才能运行。
  1. forName这句话就是装载类用的(new是根据加载到内存中的类创建一个实例,要分清楚)。
  2. 至于什么时候用,可以考虑一下这个问题,给你一个字符串变量,它代表一个类的包名和类名,你怎么实例化它? A a = (A)Class.forName("pacage.A").newInstance();这和 A a =new A();是一样的效果。
  3. jvm在装载类时会执行类的静态代码段,要记住静态代码是和class绑定的,class装载成功就表示执行了你的静态代码了,而且以后不会再执行这段静态代码了。
  4. Class.forName(xxx.xx.xx)的作用是要求JVM查找并加载指定的类,也就是说JVM会执行该类的静态代码段。
  5. 动态加载和创建Class 对象,比如想根据用户输入的字符串来创建对象 String str = 用户输入的字符串 ‘Class t = Class.forName(str); t.newInstance();

文章作者: Bxan
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Bxan !
  目录