Java反射

Posted 董广明

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java反射相关的知识,希望对你有一定的参考价值。

类中类

1.  反射介绍

       反射这一概念最早由编程开发人员Smith在1982年提出,主要指应用程序访问、检测、修改自身状态与行为的能力。这一概念的提出立刻吸引了编程界的极大关注,各种研究工作随之展开,随之而来引发编程革命,出现了多种支持反射机制的面向对象语言。

在计算机科学领域,反射是指一类能够自我描述和自控制的应用。在Java编程语言中,反射是一种强有力的工具,是面向抽象编程一种实现方式,它能使代码语句更加灵活,极大提高代码的运行时装配能力。

2. 反射在java中的体现

Java反射说的是在运行状态中,对于任何一个类,我们都能够知道这个类有哪些方法和属性。对于任何一个对象,我们都能够对它的方法和属性进行调用。我们把这种动态获取对象信息和调用对象方法的功能称之为反射机制。案例:

技术图片技术图片?

https://programmer.help/blogs/reflection-and-dynamic-agent-in-mybatis.html

 

2.1  获取Class对象

反射其实是获取类的字节码文件(在JVM的世界里只会有有一份,不管以不同的方式加载多少次),也就是.class文件,那么我们就可以通过Class这个对象进行获取,有三种方式:通过类名的class属性、对象的getClass()方法和java.lang.Class的静态方法forName(“类全路径”)

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * 
 * @author dgm
 * @describe "java 反射测试"
 * @date 2020年5月11日
 */
public class ReflectionClassTest {

	public static void main(String[] args) {
        //获取Class对象(三种方式)
		Class<?> ChildClassFirst = ChildClass.class;
		Class<?> ChildClassSecond = new ChildClass(1).getClass();
		Class<?> ChildClassThird = null;
		try {
			// below method is used most of the times in frameworks like JUnit
			//Spring dependency injection, Tomcat web container
			//Eclipse auto completion of method names, hibernate, Struts2 etc.
			//because ChildClass is not available at compile time
			ChildClassThird = Class.forName("code.reflection.ChildClass");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		System.out.println("first: "+ ChildClassFirst.getCanonicalName());
		System.out.println("second: "+ ChildClassSecond.getCanonicalName());
		System.out.println("third: "+ ChildClassThird.getCanonicalName());
		System.out.println(ChildClassFirst==ChildClassSecond);
        System.out.println(ChildClassFirst==ChildClassThird);
        System.out.println(ChildClassSecond==ChildClassThird);
        
	}
}
技术图片

 输出效果:

技术图片技术图片?

 

2.2  获取类所有的公共public构造器

可用getConstructors()返回类的所有公共构造器

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * 
 * @author dgm
 * @describe "java 公共构造器测试"
 * @date 2020年5月11日
 */
public class ReflectionConstructorTest {

	public static void main(String[] args) {
		// 获取Class对象(用的是java.lang.Class.forName())
		Class<?> ChildClass = null;
		// 获取所有公共构造器
		Constructor<?>[] publicConstructors = null;

		try {
			ChildClass = Class.forName("code.reflection.ChildClass");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		// 已经确定能Class对象,实际情况需要做判断类加载是否成功
		publicConstructors = ChildClass.getConstructors();
		System.out.println("公共构造器个数:" + publicConstructors.length);
		for (Constructor constructor : publicConstructors) {
			System.out.println("构造器:" + constructor);
		}
	}
}
技术图片
输出效果:

技术图片技术图片?

源文件的构造器:

技术图片技术图片?

2.3  获取类所有的公共public field属性

可用getFields()返回类的所有公共属性(包括从父类和接口继承过来的)

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * 
 * @author dgm
 * @describe "java 公共field属性测试"
 * @date 2020年5月11日
 */
public class ReflectionFieldTest {

	public static void main(String[] args) {
		// 获取Class对象(用的是java.lang.Class.forName())
		Class<?> ChildClass = null;
		// 获取所有公共field属性(包括从父类和接口继承过来的)
		Field[] publicFields  = null;

		try {
			ChildClass = Class.forName("code.reflection.ChildClass");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		// 已经确定有Class对象,实际情况需要做判断类加载是否成功
		publicFields  = ChildClass.getFields();
		System.out.println("公共field个数:" + publicFields .length);
		for (Field field : publicFields ) {
			System.out.println("field属性:" + field);
		}
	}
}
技术图片

输出效果:

技术图片技术图片?

 

2.4  获取类所有的公共public方法

可用getMethods()返回类的所有公共方法(包括从父类和接口继承过来的)

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * 
 * @author dgm
 * @describe "java 公共方法测试"
 * @date 2020年5月11日
 */
public class ReflectionMethodTest {

	public static void main(String[] args) {
		// 获取Class对象(用的是java.lang.Class.forName())
		Class<?> ChildClass = null;
		// 获取所有公共public方法(包括从父类和接口继承过来的)
		Method[] publicMethods  = null;

		try {
			ChildClass = Class.forName("code.reflection.ChildClass");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		// 已经确定有Class对象,实际情况需要做判断类加载是否成功
		publicMethods  = ChildClass.getMethods();
		System.out.println("公共方法个数:" + publicMethods .length);
		for (Method method : publicMethods ) {
			System.out.println("公共方法:" + method);
		}
	}
}
技术图片

输出:

技术图片技术图片?

 

2.5  获取类所有的注解

可用getAnnotations()返回类的所有注解

@Deprecated
public class ChildClass extends BaseClass implements BaseInterface {
。。。。。。
}
技术图片

测试代码:

/**
 * 
 * @author dgm
 * @describe "java 注解测试"
 * @date 2020年5月11日
 */
public class ReflectionAnnotationTest {

	public static void main(String[] args) {
		// 获取Class对象(用的是java.lang.Class.forName())
		Class<?> ChildClass = null;
		// 获取所有注解
		Annotation[] annotations  = null;

		try {
			ChildClass = Class.forName("code.reflection.ChildClass");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		// 已经确定有Class对象,实际情况需要做判断类加载是否成功
		annotations  = ChildClass.getAnnotations();
		System.out.println("注解个数:" + annotations .length);
		for (Annotation annotation : annotations ) {
			System.out.println("注解:" + annotation);
		}
	}
}
技术图片

输出效果:

技术图片技术图片?

 

3.  如何使用通过反射得到构造器、field属性、方法、注解

3.1  使用构造器

既可以一次性获取所有构造器,不过也可以单独参数化获取构造器

public class ReflectionConstructorUseTest {

	public static void main(String[] args) throws NoSuchMethodException, SecurityException, ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		// 获取Class对象(用的是java.lang.Class.forName())
		Class<?> ChildClass = null;
		// 获取所有公共构造器
		Constructor<?>[] publicConstructors = null;

		try {
			ChildClass = Class.forName("code.reflection.ChildClass");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		// 已经确定有Class对象,实际情况需要做判断类加载是否成功
		publicConstructors = ChildClass.getConstructors();
		System.out.println("公共构造器个数:" + publicConstructors.length);
		for (Constructor constructor : publicConstructors) {
			System.out.println("构造器:" + constructor);
			/*Class[] ParameterTypes = constructor.getParameterTypes();
			if(ParameterTypes.length>0) {
				Object myObj = constructor.newInstance(10);

			}*/
		}
		
		//获取构造器(没有获取所有构造器,“参数化”获取构造器),测试我是获取第一个构造器
		//框架里喜欢这样写代码,但码农式开发是不需要这样写的
		Constructor<?> constructor = ChildClass.getConstructor(int.class);
		System.out.println(Arrays.toString(constructor.getParameterTypes()));
		//用获取到的构造器实例化对象
		Object object = constructor.newInstance(99);
		
		//通过“参数化”获取类里的方法
		Method method = ChildClass.getMethod("method1", null);
		//执行方法
		method.invoke(object, null);
		
		//获取其他方法(看需求了)
		method = ChildClass.getMethod("method2", String.class);
		method.invoke(object, "dongguagming");
	}
}
技术图片

输出效果:

技术图片技术图片?

3.2  使用方法

既可以一次性获取所有方法,不过也可以单独参数化获取方法

3.2.1 获取公有方法(参数化和非参数化)

/**
 * 
 * @author dgm
 * @describe "java 方法使用测试"
 * @date 2020年5月11日
 */
public class ReflectionMethodUseTest {

	public static void main(String[] args) throws NoSuchMethodException, SecurityException, ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		// 获取Class对象(用的是java.lang.Class.forName())
		Class<?> ChildClass = null;
		try {
			ChildClass = Class.forName("code.reflection.ChildClass");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		
		//获取构造器(没有获取所有构造器,“参数化”获取构造器),测试我是获取第一个构造器
		Constructor<?> constructor = ChildClass.getConstructor(int.class);
		System.out.println(Arrays.toString(constructor.getParameterTypes()));
		//用获取到的构造器实例化对象
		Object object = constructor.newInstance(99);
		
		//通过“参数化”获取类里的公用方法
		Method method = ChildClass.getMethod("method1", null);
		//执行方法
		method.invoke(object, null);
		
		//获取其他共有方法(看需求了)
		method = ChildClass.getMethod("method2", String.class);
		method.invoke(object, ",方法 dongguagming");

	}
}
技术图片

3.2.2  获取私有方法(无参和有参数化)

/**
 * 
 * @author dgm
 * @describe "java 方法使用测试"
 * @date 2020年5月11日
 */
public class ReflectionMethodUseTest {

	public static void main(String[] args) throws NoSuchMethodException, SecurityException, ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		// 获取Class对象(用的是java.lang.Class.forName())
		Class<?> ChildClass = null;
		try {
			ChildClass = Class.forName("code.reflection.ChildClass");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		
		//获取构造器(没有获取所有构造器,“参数化”获取构造器),测试我是获取第一个构造器
		Constructor<?> constructor = ChildClass.getConstructor(int.class);
		System.out.println(Arrays.toString(constructor.getParameterTypes()));
		//用获取到的构造器实例化对象
		Object object = constructor.newInstance(99);
		
		//通过“参数化”获取类里的公用方法
		Method method = ChildClass.getMethod("method1", null);
		//执行方法
		method.invoke(object, null);
		
		//获取其他共有方法(看需求了)
		method = ChildClass.getMethod("method2", String.class);
		method.invoke(object, ",方法 dongguagming");
		
		//获取private私有方法
		Class<?> baseClass = Class.forName("code.reflection.BaseClass");
		
		method = baseClass.getDeclaredMethod("method3", null);
		method.setAccessible(true);
		//执行私有方法
		method.invoke(object, null);
		
		method = baseClass.getDeclaredMethod("method3", String.class);
		method.setAccessible(true);
		//执行私有方法
		method.invoke(object, ",确实是私有方法有参");
	}
}
技术图片

 最终输出:

技术图片技术图片?

3.3 使用field属性

3.3.1  参数化获取某个具体的field属性

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

/**
 * 
 * @author dgm
 * @describe "java Field使用测试"
 * @date 2020年5月11日
 */
public class ReflectionFieldUseTest {

	public static void main(String[] args) throws NoSuchMethodException, SecurityException, ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchFieldException {
		// 获取Class对象(用的是java.lang.Class.forName())
		Class<?> baseClass = null;
		Class<?> ChildClass = null;
		
		try {
			baseClass = Class.forName("code.reflection.BaseClass");
			ChildClass = Class.forName("code.reflection.ChildClass");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		Field field = ChildClass.getField("interfaceInt");
		System.out.println("field属性:"+field);
	}
}
技术图片

输出:

技术图片技术图片?

3.3.2  获取field属性的从属类或接口

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

/**
 * 
 * @author dgm
 * @describe "java Field使用测试"
 * @date 2020年5月11日
 */
public class ReflectionFieldUseTest {

	public static void main(String[] args) throws NoSuchMethodException, SecurityException, ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchFieldException {
		// 获取Class对象(用的是java.lang.Class.forName())
		Class<?> baseClass = null;
		Class<?> ChildClass = null;
		
		try {
			baseClass = Class.forName("code.reflection.BaseClass");
			ChildClass = Class.forName("code.reflection.ChildClass");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		Field field = ChildClass.getField("interfaceInt");
		//System.out.println("field属性:"+field);
		Class<?> fieldClass = field.getDeclaringClass();
		System.out.println("field属性在:"+fieldClass.getCanonicalName()+"中定义");
	}
}
技术图片

输出:

技术图片技术图片?

 

3.3.3  获取field属性的类

只写了核心代码“:

Field field = ChildClass.getField("interfaceInt");
Class<?> fieldType = field.getType();
System.out.println("field属性的类型是:"+fieldType.getCanonicalName()); 
技术图片

 技术图片技术图片?

 

3.3.4  设置和获取公用public field属性的值

只写了核心代码“:

field = ChildClass.getField("publicInt");
		//获取构造器(没有获取所有构造器,“参数化”获取构造器),测试我是获取第一个构造器
		Constructor<?> constructor = ChildClass.getConstructor(int.class);
		//用获取到的构造器实例化对象
		Object object = constructor.newInstance(99);
		System.out.println("field属性的值是:"+field.get(object));
		//设置field属性的值
		field.setInt(object, 100); 
		System.out.println("field属性的值是:"+field.get(object)); 
技术图片

输出:

技术图片技术图片?

 

3.3.5  设置和获取私有private field属性的值

只写了核心代码“:

//获取私有private field
		Field privateField = ChildClass.getDeclaredField("privateString");
		privateField.setAccessible(true);
		System.out.println("私有field属性的默认值是:"+privateField.get(object));
		//设置私有field属性的值
		privateField.set(object, "哪怕你是私有,我也要更改你的值"); 
		System.out.println("私有field属性的更改之后的值是:"+privateField.get(object)); 
技术图片

输出:技术图片技术图片?

 

3.4 使用注解

不细分了,要不然又写不完了

定义注解

@Documented
@Target({ElementType.TYPE, ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomAnnotation {

	public String name();
	public String value();
}
技术图片

具体类中使用,只写核心代码:

@CustomAnnotation(name="ChildClass level",  value = "ChildClass Class Annotation")


@CustomAnnotation(name="public field level",  value = "public field Annotation")
	public int publicInt;

@Override
	@CustomAnnotation(name="method1 level",  value = "Method1  Annotation ")
	public void method1() {
		System.out.println("我是无参公共public方法 Method1 impl.");
	}

	@Override
	@CustomAnnotation(name="method2 level",  value = "Method2  Annotation ")
	public int method2(String str) {
		System.out.println("我是有参公共public方法 Method2 impl." +str);
		return 0;
	}
技术图片

测试代码:

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * 
 * @author dgm
 * @describe "java 注解测试"
 * @date 2020年5月11日
 */
public class ReflectionAnnotationUseTest {

	public static void main(String[] args) {
		
		 //获取Class对象(三种方式)
		Class<?> ChildClassFirst = ChildClass.class;
		Class<?> ChildClassSecond = new ChildClass(1).getClass();
		Class<?> ChildClassThird = null;
		try {
			// below method is used most of the times in frameworks like JUnit
			//Spring dependency injection, Tomcat web container
			//Eclipse auto completion of method names, hibernate, Struts2 etc.
			//because ChildClass is not available at compile time
			ChildClassThird = Class.forName("code.reflection.ChildClass");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		System.out.println(ChildClassFirst==ChildClassSecond);
        System.out.println(ChildClassFirst==ChildClassThird);
        System.out.println(ChildClassSecond==ChildClassThird);

		// 获取类的所有注解
		Annotation[] classAnnotation = ChildClassFirst.getAnnotations();
		System.out.println(ChildClassFirst.getName()+"有"+classAnnotation.length+"个注解");
		for (Annotation ca : classAnnotation) {
			if (ca instanceof CustomAnnotation) {
				CustomAnnotation customAnnotation = (CustomAnnotation) ca;
				System.out.println("class name: " + customAnnotation.name());
				System.out.println("class value: " + customAnnotation.value());
			}
		}

		// 获取类的公有field
		Field[] fields = ChildClassFirst.getFields();
		for (Field field : fields) {
			field.setAccessible(true);
			Annotation[] fieldAnnotation = field.getAnnotations();
			for (Annotation fa : fieldAnnotation) {
				System.out.println(field.getName()+"有"+fieldAnnotation.length+"个注解");
				if (fa instanceof CustomAnnotation) {
					CustomAnnotation customAnnotation = (CustomAnnotation) fa;
					System.out
							.println("field name: " + customAnnotation.name());
					System.out.println("field value: "
							+ customAnnotation.value());

				}
			}
		}

		// 获取类的公有方法
		Method[] methods = ChildClassFirst.getMethods();
		for (Method method : methods) {
			method.setAccessible(true);
			Annotation[] methodAnnotation = method.getAnnotations();
			for (Annotation ma : methodAnnotation) {
				System.out.println(method.getName()+"有"+methodAnnotation.length+"个注解");
				if (ma instanceof CustomAnnotation) {
					CustomAnnotation customAnnotation = (CustomAnnotation) ma;
					System.out.println("method name: "
							+ customAnnotation.name());
					System.out.println("method value: "
							+ customAnnotation.value());
				}
			}
		}
	}
}
技术图片

 

出结果:

 技术图片技术图片?

总结:  构造器、方法、注解,一句话反射很重要!!!

 

参考:

0 java反射 : https://baike.baidu.com/item/JAVA%E5%8F%8D%E5%B0%84%E6%9C%BA%E5%88%B6/6015990?fr=aladdin

1. Interface AnnotatedElement

https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/AnnotatedElement.html

2.   Reflection and Dynamic Agent in Mybatis 

https://programmer.help/blogs/reflection-and-dynamic-agent-in-mybatis.html

以上是关于Java反射的主要内容,如果未能解决你的问题,请参考以下文章

反射机制入门

反射机制入门

反射机制入门

使用反射在外部JAR / CLASS上调用包含Hibernate事务的方法(Java EE)

为啥我的 Ray March 片段着色器反射纹理查找会减慢我的帧速率?

OpenGL片段着色器不照亮场景