1.反射系列:Method

本文深入解析Java反射API中的Method类,详细介绍了通过反射获取方法信息的过程,包括方法的注解、修饰符、泛型参数、返回值、名称、参数及异常。并通过一个具体示例演示了如何使用反射调用方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

https://blog.youkuaiyun.com/zhangquanit/article/details/52927216
Method 提供关于类或接口上单独某个方法(以及如何访问该方法)的信息。
一个完整方法包含的属性有:
方法上使用的注解、方法的修饰符、方法上定义的泛型参数、方法的返回值、方法名称、方法参数(泛型、注解)、方法抛出的异常。
比如下面这个方法:

@MyAnnotation
public <T> boolean add(List<T> list,T...params)throws RuntimeException,Exception{
	if(null==list){
		throw new RuntimeException("list=null");
	}
	
	if(null==params){
		return false;
	}
	//将参数添加到List集合中
	if(null!=params){
		for(T t:params){
			list.add(t);
		}
	}
	return true;
}

注解:@MyAnnotation
修饰符:public
泛型参数:T
返回值:boolean
方法名:add
方法参数(泛型、注解):List list,T…params
抛出的异常:RuntimeException,Exception

---------------------
package reflect;
 
import java.lang.annotation.Annotation;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
 
/**
 * @author zhangquanit
 */
public class MethodTest {
 
	/**
	 * 一个完整方法包含的属性有: 方法上使用的注解、方法的修饰符、方法上定义的泛型参数、方法的返回值、方法名称、方法参数(泛型、注解)、方法抛出的异常
	 */
	@MyAnnotation
	private <T> boolean add(@MyAnnotation List<T> list, T... params) throws RuntimeException,
			Exception {
		if (null == list) {
			throw new RuntimeException("list=null");
		}
 
		if (null == params) {
			return false;
		}
		// 将参数添加到List集合中
		if (null != params) {
			for (T t : params) {
				list.add(t);
			}
		}
		return true;
	}
 
	public static void main(String[] args) throws Exception {
		// 获取Method
		MethodTest obj = new MethodTest();
		Class<? extends MethodTest> clazz = obj.getClass();
 
		Method method = clazz.getDeclaredMethod("add", List.class,
				Object[].class);
		if (!method.isAccessible()) {
			method.setAccessible(true);
		}
        //获取方法基本信息
		getMethodInfo(method);
		
		// 调用方法
		List<String> arrayList = new ArrayList<String>();
		method.invoke(obj, arrayList, new String[] { "1", "2" });
		System.out.println(arrayList);//[1,2]
		
		//方法定义所在的类
		Class<?> declaringClass = method.getDeclaringClass();
		
		// 如果此方法是 bridge 方法,则返回 true;
		boolean bridge = method.isBridge();
		//如果该方法是public非抽象非静态,且定义在接口中,则返回true
		boolean default1 = method.isDefault(); //false
		//如果此方法为复合方法,则返回 true;
		boolean synthetic = method.isSynthetic();//false
		// 如果将此方法的参数带有可变参数,则返回 true
		boolean varArgs = method.isVarArgs(); //true
		
		
		
	}
 
	private static void getMethodInfo(Method method) {
		// 1、获取方法上的注解
		boolean annotationPresent = method
				.isAnnotationPresent(MyAnnotation.class);
		if (annotationPresent) {
			MyAnnotation myAnnotation = method
					.getDeclaredAnnotation(MyAnnotation.class);
		}
		// 2、方法的修饰符
		int modifiers = method.getModifiers();
		String modify = Modifier.toString(modifiers);// private
		// 3、方法上定义的泛型参数
		TypeVariable<Method>[] typeParameters = method.getTypeParameters();// [T]
		// 4、方法的返回值
		Class<?> returnType = method.getReturnType();// boolean
		Type genericReturnType = method.getGenericReturnType();// boolean
		// 5、方法名称
		String name = method.getName();
		// 6、方法参数
		int parameterCount = method.getParameterCount();// 参数个数 2
		// 方法参数——泛型
		Class<?>[] parameterTypes = method.getParameterTypes();
		// 打印 [interface java.util.List, class [Ljava.lang.Object;]
		Type[] genericParameterTypes = method.getGenericParameterTypes();
		// 打印 [java.util.List<T>, T[]]
		for (Type type : genericParameterTypes) {
			if (type instanceof ParameterizedType) { // 参数类型
				System.out.println("ParameterizedType类型:" + type);
				ParameterizedType parameterizedType = (ParameterizedType) type;
				Type[] actualTypeArguments = parameterizedType
						.getActualTypeArguments();
				System.out.println("实际参数为:"
						+ Arrays.toString(actualTypeArguments));
				for (Type actualType : actualTypeArguments) {
					if (actualType instanceof WildcardType) {
						WildcardType wildcardType = (WildcardType) actualTypeArguments[0];
						System.out.println("实际参数为WildcardType类型:"
								+ wildcardType.getUpperBounds());
					} else if (actualType instanceof Class) {
						System.out.println("实际参数为Class类型:" + actualType);
					}
				}
 
			} else if (type instanceof GenericArrayType) { // 泛型数组类型 T[]
				GenericArrayType genericArrayType = (GenericArrayType) type;
				System.out.println("GenericArrayType类型:"
						+ genericArrayType.getGenericComponentType());//T
			} else if (type instanceof TypeVariable) { // 泛型变量
				System.out.println("TypeVariable类型:" + type);
			} else if (type instanceof Class) { //
				System.out.println("Class类型:" + type);
			}
		}
		/*
		 * 方法有2个参数,第一个参数list为ParameterizedType,实际参数为T,
		 * 第二个参数为GenericArrayType泛型数组类型T[],数组元素类型为T
		 */
		
		//方法参数——注解   第一个参数使用了注解
		Annotation[][] parameterAnnotations = method.getParameterAnnotations();
		Annotation myAnnotation=parameterAnnotations[0][0];
		//打印 @reflect.MyAnnotation(intValue=0)
		
 
		// 7、方法抛出的异常
		Class<?>[] exceptionTypes = method.getExceptionTypes();
		// 打印 [class java.lang.RuntimeException, class java.lang.Exception]
		Type[] genericExceptionTypes = method.getGenericExceptionTypes();
		// 打印 [class java.lang.RuntimeException, class java.lang.Exception]
 
	}
}
异常描述: java.lang.ArrayStoreException: sun.reflect.annotation.TypeNotPresentExceptionProxy java.lang.ArrayStoreException: sun.reflect.annotation.TypeNotPresentExceptionProxy at sun.reflect.annotation.AnnotationParser.parseClassArray(AnnotationParser.java:724) at sun.reflect.annotation.AnnotationParser.parseArray(AnnotationParser.java:531) at sun.reflect.annotation.AnnotationParser.parseMemberValue(AnnotationParser.java:355) at sun.reflect.annotation.AnnotationParser.parseAnnotation2(AnnotationParser.java:286) at sun.reflect.annotation.AnnotationParser.parseAnnotations2(AnnotationParser.java:120) at sun.reflect.annotation.AnnotationParser.parseAnnotations(AnnotationParser.java:72) at java.lang.reflect.Executable.declaredAnnotations(Executable.java:599) at java.lang.reflect.Executable.declaredAnnotations(Executable.java:597) at java.lang.reflect.Executable.getDeclaredAnnotations(Executable.java:588) at java.lang.reflect.Method.getDeclaredAnnotations(Method.java:630) at org.springframework.core.annotation.AnnotationsScanner.getDeclaredAnnotations(AnnotationsScanner.java:453) at org.springframework.core.annotation.AnnotationsScanner.isKnownEmpty(AnnotationsScanner.java:491) at org.springframework.core.annotation.TypeMappedAnnotations.from(TypeMappedAnnotations.java:251) at org.springframework.core.annotation.MergedAnnotations.from(MergedAnnotations.java:351) at org.springframework.core.annotation.MergedAnnotations.from(MergedAnnotations.java:330) at org.springframework.core.annotation.AnnotatedElementUtils.findAnnotations(AnnotatedElementUtils.java:800) at org.springframework.core.annotation.AnnotatedElementUtils.hasAnnotation(AnnotatedElementUtils.java:541)怎么解决
03-28
<think>嗯,用户遇到了一个Java异常:java.lang.ArrayStoreException: sun.reflect.annotation.TypeNotPresentExceptionProxy。首先,我需要分析这个异常的原因可能的解决方案。 首先,查看异常类型。ArrayStoreException通常发生在试图将错误类型的对象存储到对象数组中时。这里的详细消息提到了sun.reflect.annotation.TypeNotPresentExceptionProxy,这可能与注解处理有关,特别是在Spring框架中。 接下来看堆栈跟踪,问题发生在AnnotationParser.parseClassArray,说明在处理注解数组时出现了问题。可能的原因是某个注解引用了缺失的类,导致TypeNotPresentExceptionProxy被创建,当尝试将这个代理对象存入数组时,类型不匹配,从而抛出ArrayStoreException。 用户的应用涉及Spring框架,特别是在处理注解时,如AnnotatedElementUtils.hasAnnotation。这可能发生在类路径中缺少某个注解所依赖的类的情况下。例如,使用了某个需要额外库的Spring注解,但该库未正确引入。 可能的解决步骤包括: 1. 检查类路径是否完整,确保所有依赖项都存在。特别是查看是否有缺失的库或版本冲突。例如,Spring可能需要某个特定的库,而项目中没有包含。 2. 检查代码中的注解,确认是否有注解引用了不存在的类。例如,自定义注解或第三方库中的注解可能引用了其他未包含的类。 3. 使用Maven或Gradle的依赖树分析工具,查看是否存在依赖冲突或缺失。例如,运行mvn dependency:tree或gradle dependencies,找出问题所在。 4. 清理并重新构建项目,有时候旧的编译文件可能导致类加载问题。 5. 检查JDK版本是否兼容。某些注解可能在较新的JDK中出现问题,或者需要特定的编译器设置。 此外,考虑是否有动态生成注解的情况,或者使用了反射操作注解数组,导致类型不一致。 需要指导用户逐步排查这些可能性,确保所有相关依赖正确,注解使用正确,并处理任何缺失的类或版本问题。</think>这个异常通常发生在Java注解处理过程中遇到类缺失的情况。以下是分步排查解决方案: 1. **检查类路径完整性** - 查看pom.xml/gradle.build中是否缺少依赖 - 特别检查与注解相关的依赖(如Spring Boot Starter系列) - 运行`mvn dependency:tree | grep "missing-class"`查找缺失类 2. **定位问题注解** - 检查堆栈涉及的方法/类上的注解声明 - 特别注意组合注解中的嵌套引用,例如: ```java @RestController // 检查是否引用了不存在的类 @ConditionalOnClass(MissingClass.class) // 显式类引用 ``` 3. **常见问题场景** ✅ 正确示例(完整依赖): ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> ``` ❌ 错误示例(缺少Jackson): ```java @JsonSerialize(using = MissingSerializer.class) // 需要jackson-databind public class MyBean {} ``` 4. **验证步骤** ```bash # Maven项目验证命令 mvn clean compile # 检查输出中是否有ClassNotFoundException # Gradle项目验证命令 gradle clean build --stacktrace ``` 5. **解决方案矩阵** | 问题类型 | 表现特征 | 解决方法 | |---------|---------|---------| | 直接依赖缺失 | 明确提示缺少某个类 | 添加对应依赖 | | 传递依赖冲突 | 存在多个版本号 | 使用`<exclusion>排除冲突版本 | | 条件化注解误用 | 使用@ConditionalXXX注解时条件不满足 | 检查条件表达式是否正确 | | 注解处理器问题 | 编译时出现错误 | 更新annotation-processor版本 | 6. **特殊案例处理** 当使用Spring Profile时,确保配置一致性: ```properties # application-dev.properties spring.config.activate.on-profile=dev missing.configuration=enabled # 确保这个配置存在的类在类路径中 ``` 建议使用IDEA的`Analyze Stacktrace`功能直接定位到问题注解所在位置。如果使用Spring Boot,可以尝试添加: ```java @SpringBootApplication(exclude = {ProblematicAutoConfiguration.class}) ``` 临时排除可疑的自动配置类来验证问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值