反射—框架设计的灵魂

一、反射概述

1、什么是反射?

将类的各个组成部分封装为其他对象,这就是反射机制。

我们来看一下java代码在计算机中经历的三个阶段
在这里插入图片描述

将类的成员变量封装为Filed对象,将类的构造方法封装Constructor对象,将成员方法封装为Method对象。

2、反射有什么好处呢?

  • 可以在程序运行过程中,操作这些对象。

举个例子:我们创建一个对象(比如String)时,当输入对象名.的时候,出现一大堆方法提示,那么这些方法从哪来呢?其实它内部用的就是反射机制。我们定义了一个字符串,则会将字符串的字节码文件加载进内存,在内存中,有一个Class类对象,Class类对象将String类的所有方法抽取出来封装成Method对象,然后将所有方法放到一个Method[]数组中,然后将其方法展示在列表中。(见下图)
在这里插入图片描述

  • 可以解耦,提高程序的可扩展性。

二、反射_获取字节码Class类对象

获取Class对象的方式有三种,分别对应java代码经历的三个阶段。

1、Class.forName("全类名“):将字节码文件加载进内存,返回Class对象。
     多用于配置文件,将类名定义在配置文件中。读取文件,加载类。
2、类名.class():通过类名的属性class获取。
     多用于参数的传递。
3、对象.getClass():etClass()方法在Object类中定义。
     多用于对象的获取字节码方式。

代码:


	public static void main(String[] args) throws ClassNotFoundException {
		
		// 1、全类名
		Class cls1 = Class.forName("cn.reflect.Person");
		System.out.println(cls1);
		
		// 2、类名.class
		Class cls2 = Person.class;
		System.out.println(cls2);
		
		// 3、对象.getclass()
		Person person = new Person();
		Class cls3 = person.getClass();
		System.out.println(cls3);
		
		System.out.println(cls1 == cls2);//输出true
		System.out.println(cls2 == cls3);//输出true

	}

结论:同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个。

三、反射_Class对象功能

Class获取常用对象功能

带declared不考虑修饰符,不带declared的只用获取public修饰的。
1、获取Filed
      Field[] getFields():获取所有public修饰的成员变量
      Field getField(String name) 获取指定名称的public修饰的成员变量
      Filed[] getDeclaredFields() 获取所有的成员变量,不考虑修饰符
      Filed[] getDeclaredFields(String name) 获取指定的成员变量,不考虑修饰符
2、获取Constructor
      Constructor<?>[] getConstuctors()
      Constructor getConstructor(类<?>…parameterTypes)
      Constructor<?>[] getDeclaredConstuctors()
      Constructor getDeclaredConstructor(类<?>…parameterTypes)
3、获取Method
      Method[] getMethods():
      Method[] getMethod(String name,类<?>…parameterTypes)
      Method[] getDeclaredMethods():
      Method[] getDeclaredMethod(String name,类<?>…parameterTypes)
4、获取类名
      String getName();

1、获取成员变量

public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException,
			IllegalArgumentException, IllegalAccessException {

		// 获取Class类对象
		Class personClass = Person.class;
		System.out.println(personClass);

		/*
		  Field[] getFields():获取所有public修饰的成员变量
          Field getField(String name) 获取指定名称的public修饰的成员变量
 
          Filed[] getDeclaredFields() 获取所有的成员变量,不考虑修饰符
          Filed[] getDeclaredFields(String name) 获取指定的成员变量,不考虑修饰
		 */

		
		// 获取所有Public修饰的成员变量
		Field[] fields = personClass.getFields();

		for (Field field : fields)
			System.out.println(field);

		// 获取指定名称的成员变量,name必须是public修饰的
		Field a = personClass.getField("name");

		// 获取成员变量a的值
		Person per = new Person();
		Object value = a.get(per);
		System.out.println(value);
		// 设置a的值
		a.set(per, "Casey");
		System.out.println(per);

		// Field[] getDeclaredFields();获取所有成员变量,不考虑修饰符
		Field[] declaredFields = personClass.getDeclaredFields();
		for (Field dField : declaredFields)
			System.out.println(dField);

		Field d = personClass.getDeclaredField("id");
		// 忽略访问全权限修饰符的安全检查
		d.setAccessible(true);// 暴力反射
		Object value1 = d.get(per);
		System.out.println(value1);

	}

2、获取构造方法

public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException,
			IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		// 获取Class类对象
		Class personClass = Person.class;
		/*
		   Constructor<?>[] getConstuctors()
           Constructor<T> getConstructor(类<?>...parameterTypes)
          
           Constructor<?>[] getDeclaredConstuctors()
           Constructor<T> getDeclaredConstructor(类<?>...parameterTypes)
		 */
		
		// 获取构造方法,带有一个int 型的参数
		Constructor constructor = personClass.getConstructor(int.class);
		constructor.setAccessible(true);
		System.out.println(constructor);
		// 创建对象
		Object per = constructor.newInstance(123);
		System.out.println(per);
		
		//空参构造
		Constructor constructor1 = personClass.getConstructor();
		constructor1.setAccessible(true);
		System.out.println(constructor1);
		// 创建对象
		Object per1 = constructor1.newInstance(123);
		System.out.println(per1);
		
		
		//空参构造可以简化
		Object per2 = personClass.newInstance();
		System.out.println(per2);
	}

3、获取成员方法

public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException,
			IllegalArgumentException, InvocationTargetException {

		Class personClass = Person.class;
		/*
		 * public修饰的方法 Method[] getMethods(): Method[] getMethod(String
		 * name,类<?>...parameterTypes)
		 * 
		 * 不考虑修饰符 Method[] getDeclaredMethods(): Method[]
		 * getDeclaredMethod(String name,类<?>...parameterTypes)
		 */

		// 获取指定名称的方法
		Method eat = personClass.getMethod("eat");
		Person p = new Person();
		// 执行方法
		eat.invoke(p);

		// 获取带有参数的方法
		Method eat1 = personClass.getMethod("eat", String.class);
		eat1.invoke(p, "food");

		// 获取所有public方法,包括object中的public方法
		Method[] methods = personClass.getMethods();
		for (Method m : methods) {
			m.setAccessible(true);// 暴力反射,私有的也能被访问
			System.out.println(m);
		}
		// 获取类里面所有方法
		Method[] methods1 = personClass.getDeclaredMethods();
		for (Method m : methods1) {
			m.setAccessible(true);// 暴力反射
			System.out.println(m);
		}

	}

4、获取类名

       //获取类名
       String className = personClass.getName();
       System.out.println(className);

猜你喜欢

转载自blog.csdn.net/weixin_44736475/article/details/105881937
今日推荐