Java 反射

Java 反射

###

文章目录

1、什么是反射

Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法。本质是JVM得到class对象之后,再通过class对象进行反编译,从而获取对象的各种信息。

Java属于先编译再运行的语言,程序中对象的类型在编译期就确定下来了,而当程序在运行时可能需要动态加载某些类,这些类因为之前用不到,所以没有被加载到JVM。通过反射,可以在运行时动态地创建对象并调用其属性,不需要提前在编译期知道运行的对象是谁。


2、反射的原理

下图是类的正常加载过程、反射原理与class对象:

Class对象的由来是将.class文件读入内存,并为之创建一个Class对象。

在这里插入图片描述


3、反射的优缺点

优点

  1. 在运行时获得类的各种内容,进行反编译,对于Java这种先编译再运行的语言,能够让我们很方便的创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代码的链接,更加容易实现面向对象。

  2. 允许程序创建和控制任何类的对象,无需提前硬编码目标类

  3. 提高了Java程序的灵活性和扩展性,降低了耦合性,提高自适应能力

  4. 反射的应用领域 (开源框架,如MyBatis、Spring等)

缺点

  1. 性能问题

反射会消耗一定的系统资源,因此,如果不需要动态地创建一个对象,那么就不需要用反射

反射机制主要应用在对灵活性和扩展性要求很高的系统框架上

  1. 代码维护问题

反射会模糊程序内部逻辑,可读性较差.

反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题


4、反射的用途

  1. 反编译:.class–>.java

  2. 通过反射机制访问java对象的属性,方法,构造方法等

  3. 当我们在使用IDEA,比如Ecplise时,当我们输入一个对象或者类,并想调用他的属性和方法是,一按点号,编译器就会自动列出他的属性或者方法,这里就是用到反射。

  4. 反射最重要的用途就是开发各种通用框架。比如很多框架(Spring)都是配置化的(比如通过XML文件配置Bean),为了保证框架的通用性,他们可能需要根据配置文件加载不同的类或者对象,调用不同的方法,这个时候就必须使用到反射了,运行时动态加载需要的加载的对象。


5、反射技术常用API

反射常用的Java类型

java.lang.Class<T>              //可获取类和类的成员信息 
java.lang.reflect.Constructor<T>//可调用类的构造方法
java.lang.reflect.Field         //可访问类的属性  
java.lang.reflect.Method        //可调用类的方法 

6、反射技术使用步骤

  1. 导入 java.lang.reflect.*

  2. 获得需要操作的类的java.lang.Class对象

  3. 调用Class的方法获取Field、Method等对象

  4. 使用反射API操作实例成员


7、反射的入口类Class

Class类是Java反射机制的起源和入口

  • 每个类都有自己向关的Class对象

  • 提供了获取类信息的相关方法

Class类存放类的结构信息

  • 类名

  • 父类﹑接口

  • 构造方法﹑方法﹑属性

  • 注解

  • ……

获取Class实例常用方式

//方法1:对象.getClass()
Student stu = new Student();
Class clazz = stu.getClass();           
//方法2:类.class
Class clazz = Student.class;    
//方法3:Class.forName()
Class clazz = Class.forName("xxx.xxx.Student");

获取类型的基本信息的常用方法:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LfWlVmKt-1665402813400)(E:\Aiden_EDU\Courseware\FrameFoundation\反射.assets\1665382352816.png)]


定一个BaseClass为父类

package reflect.entity;
​
public class BaseClass {
​
}

定一个Person类并继承BaseClass父类实现Serializable接口

package reflect.entity;
​
import java.io.Serializable;
import java.io.IOException;
​
public final class Person extends BaseClass implements Serializable {
​
    // 成员变量
    private String name;
    static final int age = 30;
    protected String address;
    public String message;
​
    // 成员方法
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    static final int getAge() {
        return age;
    }
    protected String getAddress() {
        return address;
    }
    private void silentMethod() throws IOException, NullPointerException {
        System.out.println("这是悄悄话");
    }
​
    /*[以下声明用于通过反射获取构造方法信息测试]*/
    //无参构造函数
    public Person() { }
    //有参构造函数
    private Person(String name) {
        this.name = name;
    }
​
    protected Person(String name, String address, String message) {
        this.name = name;
        this.address = address;
        this.message = message;
    }
    
    @Override
    public String toString() {
        return "{name:" + name + ", age:" + age + ", address:" + address
                + ", message:" + message + "}";
    }
}

通过反射获取类的信息示例:

package reflect.classinfo;
​
import java.lang.reflect.Modifier;
​
import reflect.entity.Person;
​
/**
 * 获取类型的基本信息
*/
public class GetClassInfo {
    
    public static void main(String[] args) {
        Class clz = Person.class;
        String fullName = clz.getName();
        String simpleName = clz.getSimpleName();
        System.out.println("以下是 " + fullName + " 类的基本信息");
​
        // 获取Person类所在的包
        Package pkg = clz.getPackage();
​
        // 获得此对象所表示的实体(类、接口、基本类型或 void)的超类的 Class
        // 如果此对象表示 Object 类、一个接口、一个基本类型或 void,则返回 null
        // 如果此对象表示一个数组类,则返回表示该 Object 类的 Class 对象
        Class superClass = clz.getSuperclass();
        System.out.println(simpleName + " 类的超类是:" + superClass.getName());
​
        // 获得此对象所表示的类或接口实现的接口
        // 如果此对象表示一个不实现任何接口的类或接口,则此方法返回一个长度为 0 的数组。
        // 如果此对象表示一个基本类型或 void,则此方法返回一个长度为 0 的数组。
        Class[] interfaces = clz.getInterfaces();
​
        //getModifiers()方法返回int类型值表示该字段的修饰符。其中,该修饰符是java.lang.reflect.Modifier的静态属性
        int modifier = clz.getModifiers();
    }
}

获取构造方法信息的常用方法:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lDqsPJEZ-1665402813401)(E:\Aiden_EDU\Courseware\FrameFoundation\反射.assets\1665382512042.png)]

获取构造方法信息示例代码:

package reflect.classinfo;
​
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
​
import reflect.entity.Person;
​
/**
 * 获取构造方法信息
*/
public class GetClassConstructorsInfo {
​
    public static void main(String[] args) {
​
        // 获取Person类声明的所有构造方法
        // 它们是公共、保护、默认(包)访问和私有构造方法
        // 如果此 Class 实例表示一个接口、一个基本类型、一个数组类或 void,则此方法返回一个长度为 0 的数组
        Constructor[] cons = Person.class.getDeclaredConstructors();
​
        // 构造方法的一些信息
        System.out.println("=========构造方法展示=========");
        for (Constructor con : cons) {
            System.out.print("访问修饰符:");
            int modifier = con.getModifiers();
            // 判断该构造方法的访问修饰符
            if ((modifier & Modifier.PUBLIC) == Modifier.PUBLIC)
                System.out.println("public");
            else if ((modifier & Modifier.PROTECTED) == Modifier.PROTECTED)
                System.out.println("protected");
            else if ((modifier & Modifier.PRIVATE) == Modifier.PRIVATE)
                System.out.println("private");
            else System.out.println("default(package)");
            
            // 获取构造方法的参数列表
            Class[] params = con.getParameterTypes();
            if (params.length == 0) {
                System.out.println("该构造方法没有参数");
            } else {
                System.out.print("该构造方法的参数列表为:[");
                for (int i = 0; i < params.length; i++) {
                    if (i != 0)System.out.print(", ");
                    System.out.print(params[i].getName());
                }
                System.out.println("]");
            }
        }
    }
}

获取属性信息的常用方法:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Jio2hOOO-1665402813403)(E:\Aiden_EDU\Courseware\FrameFoundation\反射.assets\1665382820540.png)]

获取属性信息示例:

package reflect.classinfo;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

import reflect.entity.Person;

/**
 * 获取属性信息
 */
public class GetClassFieldsInfo {

	public static void main(String[] args) {

		// 获取Person中的所有属性,
		// 包括公共、保护、默认(包)访问和私有属性,但不包括继承的属性,
		// 如果该类或接口不声明任何属性,或者此 Class 实例表示一个基本类型、一个数组或 void,则此方法返回一个长度为 0 的数组。
		Field[] fields = Person.class.getDeclaredFields();

		// 展示属性的一些信息
		System.out.println("===========属性展示==========");
		for (Field field : fields) {
			System.out.println("属性名:" + field.getName());
			System.out.println("类型:" + field.getType().getName());

			System.out.print("访问修饰符:");
			int modifier = field.getModifiers();
			// 判断该属性的访问修饰符
			if ((modifier & Modifier.PUBLIC) == Modifier.PUBLIC)
				System.out.println("public");
			else if ((modifier & Modifier.PROTECTED) == Modifier.PROTECTED)
				System.out.println("protected");
			else if ((modifier & Modifier.PRIVATE) == Modifier.PRIVATE)
				System.out.println("private");
			else
				System.out.println("default(package)");

			// 判断该属性是否有static修饰符
			if ((modifier & Modifier.STATIC) == Modifier.STATIC)
				System.out.println("这是一个静态属性");
			// 判断该属性是否有final修饰符
			if ((modifier & Modifier.FINAL) == Modifier.FINAL)
				System.out.println("这是一个final属性");
		}
	}
}

获取方法信息的常用方法:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MD6ImM28-1665402813403)(E:\Aiden_EDU\Courseware\FrameFoundation\反射.assets\1665382948912.png)]

获取方法信息示例:

package reflect.classinfo;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

import reflect.entity.Person;

/**
 * 获取方法信息
 */
public class GetClassMethodsInfo {
	
	public static void main(String[] args) {

		// 获取Person中的所有方法,
		// 包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法,
		// 如果该类或接口不声明任何方法,或者此 Class 实例表示一个基本类型、一个数组或 void,则此方法返回一个长度为 0 的数组。
		Method[] methods = Person.class.getDeclaredMethods();

		// 展示方法的一些信息
		System.out.println("===========方法展示==========");
		for (Method method : methods) {
			System.out.println("方法名:" + method.getName());
			System.out.println("返回值类型:" + method.getReturnType().getName());

			// 获取方法的参数列表
			Class[] params = method.getParameterTypes();
			if (params.length == 0) {
				System.out.println("该方法没有参数");
			} else {
				System.out.print("该方法的参数列表为:[");
				for (int i = 0; i < params.length; i++) {
					if (i != 0)
						System.out.print(", ");
					System.out.print(params[i].getName());
				}
				System.out.println("]");
			}

			System.out.print("访问修饰符:");
			int modifier = method.getModifiers();
			// 判断该方法的访问修饰符
			if ((modifier & Modifier.PUBLIC) == Modifier.PUBLIC)
				System.out.println("public");
			else if ((modifier & Modifier.PROTECTED) == Modifier.PROTECTED)
				System.out.println("protected");
			else if ((modifier & Modifier.PRIVATE) == Modifier.PRIVATE)
				System.out.println("private");
			else
				System.out.println("default(package)");

			// 判断该方法是否有static修饰符
			if ((modifier & Modifier.STATIC) == Modifier.STATIC)
				System.out.println("这是一个静态方法");
			// 判断该方法是否有final修饰符
			if ((modifier & Modifier.FINAL) == Modifier.FINAL)
				System.out.println("这是一个final方法");
			// 判断该方法是否有abstract修饰符
			if ((modifier & Modifier.ABSTRACT) == Modifier.ABSTRACT)
				System.out.println("这是一个抽象方法");
			// 判断该方法是否有synchronized修饰符
			if ((modifier & Modifier.SYNCHRONIZED) == Modifier.SYNCHRONIZED)
				System.out.println("这是一个同步方法");

			// 获取方法所属的类或接口的Class实例
			Class declaringClass = method.getDeclaringClass();
			System.out.println("方法声明在:" + declaringClass.getName() + " 中");
			
			// 获取方法抛出的异常类型,即throws子句中声明的异常
			Class[] exceptions = method.getExceptionTypes();
			if (exceptions.length > 0) {
				System.out.print("该方法抛出的异常有:[");
				for (int i = 0; i < exceptions.length; i++) {
					if (i != 0)
						System.out.print(", ");
					System.out.print(exceptions[i].getName());
				}
				System.out.println("]");
			}
			System.out.println("----------------------------");
		}
	}
}

8、反射实现类的实例化

java.lang.Class public T newInstance()

//关键代码:
Class clazz = Class.forName("reflect.entity.Person");
Object obj = clazz.newInstance();				

java.lang.reflect.Constructor public T newInstance(Object… initargs)

Constructor cons = clazz.getDeclaredConstructor(String.class);
cons.setAccessible(true);
Object obj = cons.newInstance("New Person");
package reflect.access;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class AccessPersonConstructors {
  // 测试反射调用构造方法  
  public static void main(String[] args) {
     
     try {
         Class clz = Class.forName("reflect.entity.Person");
         Object obj = clz.newInstance();
         System.out.println(obj);

         // 获取Person的无参构造
         Constructor c1 = clz.getDeclaredConstructor();
         // Person的无参构造为public,这里可以直接访问
         obj = c1.newInstance();
         System.out.println(obj);

         // 获取Person的单参构造
         Constructor c2 = clz.getDeclaredConstructor(String.class);
         // Person的单参构造为private,这里已超出其访问范围,不能直接访问
         // 通过setAccessable方法,设定为可以访问
         c2.setAccessible(true);
         obj = c2.newInstance("New Person");
         System.out.println(obj);

         // 获取Person的三参构造
         Constructor c3 = clz.getDeclaredConstructor(String.class,
                 String.class, String.class);
         // Person的三参构造为protected,这里已超出其访问范围,不能直接访问
         // 通过setAccessable方法,设定为可以访问
         c3.setAccessible(true);
         obj = c3.newInstance("New Person", "beijing", "Hello!");
         System.out.println(obj);
     } catch (ClassNotFoundException e) {
         e.printStackTrace();
     } catch (SecurityException e) {
         e.printStackTrace();
     } catch (NoSuchMethodException e) {
         e.printStackTrace();
     } catch (IllegalArgumentException e) {
         e.printStackTrace();
     } catch (InstantiationException e) {
         e.printStackTrace();
     } catch (IllegalAccessException e) {
         e.printStackTrace();
     } catch (InvocationTargetException e) {
         e.printStackTrace();
     }
  }
}

9、反射访问实例的字段

java.lang.reflect.Field

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fpGSMo1n-1665402813404)(E:\Aiden_EDU\Courseware\FrameFoundation\反射.assets\1665383388818.png)]

package reflect.access;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

import reflect.entity.Person;

/**
 * 通过反射方式访问属性
*/
public class AccessPersonFields {
	// 通过反射操作Person的属性
	public static void main(String[] args) {
		try {
			// 通过反射加载一个Person实例
			Class cls = Class.forName("reflect.entity.Person");
			Object person = cls.newInstance();
			// 获取name属性
			Field name = cls.getDeclaredField("name");
			// name属性为private,这里已超出其访问范围,不能直接访问
			// 通过setAccessable方法,设定为可以访问
			name.setAccessible(true);
			// 先取值看一下
			System.out.println("赋值前的name:" + name.get(person));
			// 为name属性赋值
			name.set(person, "New Person");
			// 展示一下赋值效果
			System.out.println("赋值后的name:" + name.get(person));
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		}
	}
}

10、反射调用实例的方法

java.lang.reflect.Method

public  Object  invoke( Object obj, Object...args)
package reflect.access;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import reflect.entity.Person;
/**
 * 反射调用实例的方法
 */
public class AccessPersonMethods {

	public static void main(String[] args) {
		//反射操作Person的方法
		try {
			//通过反射加载Person类
			Class clz = Class.forName("reflect.entity.Person");

			//根据方法名和参数列表获取static final int getAge()方法,无参可以不写或用null表示
			Method getAge = clz.getDeclaredMethod("getAge", null);
			//getAge方法为default(package),这里已超出其访问范围,不能直接访问
			//通过setAccessable方法,设定为可以访问
			getAge.setAccessible(true);
			//调用getAge方法并传参,没有参数可以不写或用null表示
			//getAge方法为静态方法,调用时可以不指定具体Person实例
			Object returnAge = getAge.invoke(null, null);
			System.out.println("年龄是:" + returnAge);

			Object person = clz.newInstance(); //创建Person实例

			//根据方法名和参数列表获取private void silentMethod()方法
			Method silentMethod = clz.getDeclaredMethod("silentMethod", null);
			//silentMethod方法为private,这里已超出其访问范围,不能直接访问
			//通过setAccessable方法,设定为可以访问
			silentMethod.setAccessible(true);
			//调用silentMethod方法并传参,没有参数可以不写或用null表示
			silentMethod.invoke(person, null);

			//根据方法名和参数列表获取public void setName(String)方法
			Method setName = clz.getDeclaredMethod("setName", String.class);
			//setName方法为public,这里可以直接访问
			//调用setName方法并传参
			setName.invoke(person, "New Person");
			//验证一下结果,调用public String getName()方法得到name的值
			Object returnName = clz.getDeclaredMethod("getName").invoke(person);
			System.out.println("刚才设定的name是:" + returnName);

		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
	}
}

11、反射总结

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ko1Dzjvx-1665402813405)(E:\Aiden_EDU\Courseware\FrameFoundation\反射.assets\反射.png)]

文章知识点与官方知识档案匹配,可进一步学习相关知识

Java技能树首页概览130395 人正在系统学习中

本文转自 Java 反射_if((modifier & modifier.public) == modifier.public_众生云海,一念初见的博客-CSDN博客,如有侵权,请联系删除。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值