Java 反射

一、反射机制概念

主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。在java中,只要给定类的名字, 那么就可以通过反射机制来获得类的所有信息。

反射是Java中一种强大的工具,能够使我们很方便的创建灵活的代码,这些代码可以再运行时装配,无需在组件之间进行源代码链接。但是反射使用不当会成本很高!

二、反射机制的作用

  1. 在运行时判断任意一个对象所属的类;
  2. 在运行时获取类的对象;
  3. 在运行时访问java对象的属性,方法,构造方法等。

三、反射机制的优点与缺点

优点:可以实现动态创建对象和编译,体现出很大的灵活性.

编译方式说明:

  1. 静态编译:在编译时确定类型 & 绑定对象。如常见的使用new关键字创建对象

  2. 动态编译:运行时确定类型 & 绑定对象。动态编译体现了Java的灵活性、多态特性 & 降低类之间的藕合性

缺点:对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它 满足我们的要求。这类操作总是慢于只直接执行相同的操作。

四、具体使用

  • Class类

反射机制的实现主要通过操作java.lang.Class类。

在Java程序运行时,Java运行环境会为所有类维护一个java.lang.Class对象,存放着对应类型对象的运行时信息。

Java反射机制的实现除了依靠Java.lang.Class类,还需要依靠:Constructor类、Field类、Method类,分别作用于类的各个组成部分:

  • 使用步骤

在使用Java反射机制时,主要步骤包括:

  1. 获取目标类型的Class对象
  2. 通过Class对象分别获取Constructor类对象、Method类对象 & Field 类对象
  3. 通过Constructor类对象、Method类对象 & Field类对象分别获取类的构造函数、方法&属性的具体信息,并进行后续操作
1、获得class对象

(1) 使用 Class 类的 forName 静态方法

    Class<?> classtype3 = Class.forName("java.lang.Boolean");
	System.out.println(classtype3);

(2) 直接获取某一个对象的 class

    Class<?> classtype2 = Boolean.class;
	System.out.println(classtype2);
	Class<?> classtype4 = Boolean.TYPE;
	System.out.println(classtype4);

(3) 调用某个对象的 getClass() 方法

	Boolean flg = true;
	Class<?> classtype = flg.getClass();
	System.out.println(classtype);

(4) 获取父类 getSuperclass();

	Class<?> classtype4 = Class.forName("java.lang.Boolean");
	classtype4.getSuperclass();
2、判断是否为某个类的实例

一般地,我们用 instanceof 关键字来判断是否为某个类的实例。同时我们也可以借助反射中 Class 对象的 isInstance() 方法来判断是否为某个类的实例,它是一个 native 方法:

public native boolean isInstance(Object obj);
3、创建实例以及获取构造方法

(1) 使用Class对象的newInstance()方法来创建Class对象对应类的实例。

(2) 先通过Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建实例。这种方法可以用指定的构造器构造类的实例。

4、获取方法

(1) getDeclaredMethods 方法返回类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。

public Method[] getDeclaredMethods() throws SecurityException

(2) getMethods 方法返回某个类的所有公用(public)方法,包括其继承类的公用方法。

public Method[] getMethods() throws SecurityException

(3) getMethod 方法返回一个特定的方法,其中第一个参数为方法名称,后面的参数为方法的参数对应Class的对象。

public Method getMethod(String name, Class<?>... parameterTypes)
  1. getDeclaredMethod 方法返回一个特定的方法,但不包括继承的方法。
5、获取类的成员变量(字段)信息

(1) getFiled:获得指定的公有成员变量

(2) getDeclaredField:获得指定已声明的成员变量,但不能得到其父类的成员变量

(3) getFileds:获得所有公有的成员变量

(4) getDeclaredFields:获得所有已声明的成员变量,但不能得到其父类的成员变量

(5) 获取指定对象的指定字段的值 field.get(obj)

(6) 设置指定对象的指定对象Field值 field.set(obj, “123”);

6、调用方法

当我们从类中获取了一个方法后,我们就可以用 invoke() 方法来调用这个方法。invoke 方法的原型为:

public Object invoke(Object obj, Object... args)
        throws IllegalAccessException, IllegalArgumentException,
           InvocationTargetException
7、获得注解

Class类、Field类、Method类 & Constructor类对象都有如下方法

getAnnotations();

getDeclaredAnnotations();

getAnnotation(annotationClass);

8、关于private

反射机制的默认行为受限于Java的访问控制,无法访问( private )私有的方法、字段。

Java安全机制只允许查看任意对象有哪些域,而不允许读它们的值若强制读取,将抛出异常。

使用Field类、Method类 & Constructor类对象的setAccessible()可以脱离Java程序中安全管理器的控制、屏蔽Java语言的访问检查。

五、代码

public class ReflectionTest {

	public static void main(String[] args) throws Exception {

		// 1、获得class
		// 1.1 使用 Class 类的 forName 静态方法
		Class<?> class1 = Class.forName("java.lang.Boolean");
		System.out.println(class1);
		// 1.2 直接获取某一个对象的 class
		Class<?> class2 = Boolean.class;
		System.out.println(class2);
		Class<?> class3 = Boolean.TYPE;
		System.out.println(class3);
		// 1.3 调用某个对象的 getClass() 方法
		Boolean flg = true;
		Class<?> class4 = flg.getClass();
		System.out.println(class4);
		// 1.4 获取父类调用getSuperclass() 方法
		Class<?> superclass = class1.getSuperclass();
		System.out.println(superclass);

		// 2、判断是否为某个类的实例
		System.out.println(Boolean.class.isInstance(flg));

		// 3、创建实例以及获取构造器
		// 3.1 直接通过class对象创建实例
		Class<?> m4 = M4A1.class;
		Object m4obj1 = m4.newInstance();
		
		System.out.println(m4obj1.toString());
		// 3.2 通过class对象获得构造器来实例化对象
		// 获得参数的指定构造器
		Constructor constructor = m4.getConstructor(String.class,Double.class);

		// 获得所有构造器
		Constructor<?>[] constructors = m4.getConstructors();
		for(Constructor c:constructors){
			System.out.println(c);
		}
		Object m4obj2 = constructor.newInstance("步枪",38.89d);
		System.out.println(m4obj2.toString());
		
		// 4、获取方法
		// 4.1 获取所有公用方法(public)
		Method[] methods = m4.getMethods();
		for(Method m:methods){
			System.out.println(m);
		}
		// 4.2 获取所有非继承的方法
		Method[] methods2 = m4.getDeclaredMethods();
		for(Method m:methods2){
			System.out.println(m);
		}
		// 4.3 由方法名和参数类型获取一个指定方法
		Method method = m4.getMethod("setConment", String.class);
		System.out.println(method);
		Method method2 = m4.getDeclaredMethod("toString");
		System.out.println(method2);

		// 5、获取成员变量
		// 5.1 获取指定变量
		Field field = m4.getDeclaredField("conment");
		System.out.println(field);
		Field field2 = m4.getField("name");
		System.out.println(field2);
		// 5.2 获取所有变量
		Field[] fields = m4.getFields();
		for(Field f:fields){
			System.out.println(f);
		}
		Field[] fields2 = m4.getDeclaredFields();
		for(Field f:fields2){
			System.out.println(f);
		}
		// 5.3 设定指定字段的值
		// 设置可以访问private
		field.setAccessible(true);
		field.set(m4obj1, "使用Field类的set方法设定conment的值");
		// 5.4 获取指定字段的值
		Object value = field.get(m4obj1);
		System.out.println(value);
		// 6、调用方法
		// 获得class对象
		Class<?> clazz = M4A1.class;
		// 实例化
		Object m4a1 = clazz.newInstance();
		// 获得方法
		Method setConmentMethod = clazz.getMethod("setConment",String.class);
		Method getConmentMethod = clazz.getMethod("getConment");
		Method tostringMethod = clazz.getMethod("toString");
		// 调用方法
		setConmentMethod.invoke(m4a1, "测试一下invoke调用方法");
		Object result = getConmentMethod.invoke(m4a1);
		System.out.println(result);
		System.out.println(tostringMethod.invoke(m4a1));
	}
}
public class M4A1 {

	private String conment;
	private Double might;
	public String name;

	/**
	 * @Title:M4A1
	 * @Description:TODO
	 */
	public M4A1() {
		super();
		// TODO Auto-generated constructor stub
		System.out.println("执行无参构造方法");
	}

	/**
	 * @Title:M4A1
	 * @Description:TODO
	 * @param conment
	 * @param might
	 */
	public M4A1(String conment, Double might) {
		super();
		this.conment = conment;
		this.might = might;
		System.out.println("执行带参构造方法");
	}

	/**
	 * @return the conment
	 */
	public String getConment() {
		return conment;
	}

	/**
	 * @param conment
	 *            the conment to set
	 */
	public void setConment(String conment) {
		this.conment = conment;
	}

	/**
	 * @return the might
	 */
	public Double getMight() {
		return might;
	}

	/**
	 * @param might
	 *            the might to set
	 */
	public void setMight(Double might) {
		this.might = might;
	}

	/*
	 * (non Javadoc)
	 * 
	 * @Title: toString
	 * 
	 * @Description: TODO
	 * 
	 * @return
	 * 
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return "M4A1 [conment=" + conment + ", might=" + might + "]";
	}

}

参考

https://www.jianshu.com/p/4c07f1824cd8

https://www.sczyh30.com/posts/Java/java-reflection-1/

https://www.cnblogs.com/tech-bird/p/3525336.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值