Spring 5 ParameterNameDiscoverer 源码注释

ParameterNameDiscoverer

这个 Spring 用于寻找现方法和构造函数的参数名的发现器。

/**
 * Interface to discover parameter names for methods and constructors.
 * <p>用于发现方法和构造函数的参数名的接口</p>
 * <p>Parameter name discovery is not always possible, but various strategies are
 * available to try, such as looking for debug information that may have been
 * emitted at compile time, and looking for argname annotation values optionally
 * accompanying AspectJ annotated methods.
 * <p>
 *     参数名并非总是可以发现参数名称,但可以尝试各种策略,比如寻找在编译时可能
 *     发生调试信号,和寻找可选的附带AspectJ注解方法的argname注解值
 * </p>
 * @author Rod Johnson
 * @author Adrian Colyer
 * @since 2.0
 */
public interface ParameterNameDiscoverer {
    
    

	/**
	 * Return parameter names for a method, or {@code null} if they cannot be determined.
	 * <p>
	 *     返回方法的参数名,如果不能确定就返回{@code null}
	 * </p>
	 * <p>Individual entries in the array may be {@code null} if parameter names are only
	 * available for some parameters of the given method but not for others. However,
	 * it is recommended to use stub parameter names instead wherever feasible.
	 * <p>
	 *     如果参数名称仅可用于给定方法的某些参数,而不适用于其他参数,则数组的各个条目
	 *     可能为{@code null}.但是,建议在可行的地方使用存根参数名名代替。
	 * </p>
	 * @param method the method to find parameter names for
	 *               -- 查找参数名称的方法
	 * @return an array of parameter names if the names can be resolved,
	 * or {@code null} if they cannot
	 * 			-- 如果名称能被解析就返回一组参数名,否则返回{@code null}
	 */
	@Nullable
	String[] getParameterNames(Method method);

	/**
	 * Return parameter names for a constructor, or {@code null} if they cannot be determined.
	 * <p>
	 *     返回构造函数的参数名,如果不能确定就返回{@code null}
	 * </p>
	 * <p>Individual entries in the array may be {@code null} if parameter names are only
	 * available for some parameters of the given constructor but not for others. However,
	 * it is recommended to use stub parameter names instead wherever feasible.
	 * <p>
	 *     如果参数名称仅可用于给定方法的某些参数,而不适用于其他参数,则数组的各个条目
	 *     可能为{@code null}.但是,建议在可行的地方使用存根参数名名代替。
	 * </p>
	 * @param ctor the constructor to find parameter names for
	 *             -- 查找参数名称的方法
	 * @return an array of parameter names if the names can be resolved,
	 * or {@code null} if they cannot
	 * 				-- 如果名称能被解析就返回一组参数名,否则返回{@code null}
	 */
	@Nullable
	String[] getParameterNames(Constructor<?> ctor);

}

PrioritizedParameterNameDiscoverer

/**
 * {@link ParameterNameDiscoverer} implementation that tries several discoverer
 * delegates in succession. Those added first in the {@code addDiscoverer} method
 * have highest priority. If one returns {@code null}, the next will be tried.
 * <p>陆续尝试一些发现器委托类的{@link ParameterNameDiscoverer}实现。在
 * {@code addDiscoverer}方法中最先添加的那些有效级最高。如果一个返回{@code null},
 * 尝试下一个</p>
 * <p>The default behavior is to return {@code null} if no discoverer matches.
 * <p>如果没有发现器匹配,则默认行为是返回{@code null}</p>
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @since 2.0
 */
public class PrioritizedParameterNameDiscoverer implements ParameterNameDiscoverer {
    
    

	/**
	 * 参数名发现器集合
	 */
	private final List<ParameterNameDiscoverer> parameterNameDiscoverers = new LinkedList<>();


	/**
	 * Add a further {@link ParameterNameDiscoverer} delegate to the list of
	 * discoverers that this {@code PrioritizedParameterNameDiscoverer} checks.
	 * <p>向此{@code PrioritizedParameterNameDiscoverer}检查的发现器列表添加一个
	 * {@link ParameterNameDiscoverer}委托对象</p>
	 */
	public void addDiscoverer(ParameterNameDiscoverer pnd) {
    
    
		this.parameterNameDiscoverers.add(pnd);
	}


	@Override
	@Nullable
	public String[] getParameterNames(Method method) {
    
    
		//遍历参数名发现器集合
		for (ParameterNameDiscoverer pnd : this.parameterNameDiscoverers) {
    
    
			//通过参数名发现器获取method中的参数名数组
			String[] result = pnd.getParameterNames(method);
			//如果result不为null,表示该参数名发现器能拿到method的参数名
			if (result != null) {
    
    
				//返回结果
				return result;
			}
			//如果result为null,表示该参数名发现器没法拿到method的参数名,就交给下一个参数名发现
		}
		//如果所有的参数名发现器都没法拿到参数名,就返回null
		return null;
	}

	@Override
	@Nullable
	public String[] getParameterNames(Constructor<?> ctor) {
    
    
		//遍历参数名发现器集合
		for (ParameterNameDiscoverer pnd : this.parameterNameDiscoverers) {
    
    
			//通过参数名发现器获取ctor中的参数名数组
			String[] result = pnd.getParameterNames(ctor);
			//如果result不为null,表示该参数名发现器能拿到ctor的参数名
			if (result != null) {
    
    
				//返回结果
				return result;
			}
			//如果ctor为null,表示该参数名发现器没法拿到ctor的参数名,就交给下一个参数名发现器处理
		}
		//如果所有的参数名发现器都没法拿到参数名,就返回null
		return null;
	}

}

DefaultParameterNameDiscoverer

/**
 * Default implementation of the {@link ParameterNameDiscoverer} strategy interface,
 * using the Java 8 standard reflection mechanism (if available), and falling back
 * to the ASM-based {@link LocalVariableTableParameterNameDiscoverer} for checking
 * debug information in the class file.
 * <p>{@link ParameterNameDiscoverer}策略接口的默认实现,使用Java 8标准反射机制(如果有),
 * 然后回退基于ASM的{@link LocalVariableTableParameterNameDiscoverer},以检查在类文件中
 * 调试信息。
 * </p>
 * <p>If a Kotlin reflection implementation is present,
 * {@link KotlinReflectionParameterNameDiscoverer} is added first in the list and used
 * for Kotlin classes and interfaces. When compiling or running as a Graal native image,
 * no {@link ParameterNameDiscoverer} is used.
 * <p>
 *     如果存在Kotlin反射实现,则将{@link KotlinReflectionParameterNameDiscoverer}首先添加
 *     到列表中,并将用于Kotlin类和接口。当编译或作为Graal本机映像时,不使用{@link ParameterNameDiscoverer}
 * </p>
 * <p>Further discoverers may be added through {@link #addDiscoverer(ParameterNameDiscoverer)}.
 * <p>可以通过{@link #addDiscoverer(ParameterNameDiscoverer)}添加更多发现器</p>
 * <p>GraalVM 是一个跨语言的通用虚拟机,不仅支持了 Java、Scala、Groovy、Kotlin 等基于 JVM 的语言,
 * 以及 C、C++ 等基于 LLVM 的语言,还支持其他像 JavaScript、Ruby、Python 和 R 语言等。称是一个全
 * 新的通用全栈虚拟机,并具有高性能、跨语言交互等逆天特性</p>
 * @author Juergen Hoeller
 * @author Sebastien Deleuze
 * @since 4.0
 * @see StandardReflectionParameterNameDiscoverer
 * @see LocalVariableTableParameterNameDiscoverer
 * @see KotlinReflectionParameterNameDiscoverer
 */
public class DefaultParameterNameDiscoverer extends PrioritizedParameterNameDiscoverer {
    
    

	public DefaultParameterNameDiscoverer() {
    
    
		//如果项目不是运行在GraalVM环境里
		if (!GraalDetector.inImageCode()) {
    
    
			//如果存在Kntlin反射
			if (KotlinDetector.isKotlinReflectPresent()) {
    
    
				//添加Kotlin的反射工具内省参数名发现器
				addDiscoverer(new KotlinReflectionParameterNameDiscoverer());
			}
			//添加 使用JDK8的反射工具内省参数名 (基于'-parameters'编译器标记)的参数名发现器
			addDiscoverer(new StandardReflectionParameterNameDiscoverer());
			//添加 基于ASM库对Class文件的解析获取LocalVariableTable信息来发现参数名 的参数名发现器
			addDiscoverer(new LocalVariableTableParameterNameDiscoverer());
		}
	}

}

StandardReflectionParameterNameDiscoverer

/**
 * {@link ParameterNameDiscoverer} implementation which uses JDK 8's reflection facilities
 * for introspecting parameter names (based on the "-parameters" compiler flag).
 * <p>{@link ParameterNameDiscoverer}实现类,使用JDK8的反射工具内省参数名
 * (基于'-parameters'编译器标记)</p>
 * @author Juergen Hoeller
 * @since 4.0
 * @see java.lang.reflect.Method#getParameters()
 * @see java.lang.reflect.Parameter#getName()
 */
public class StandardReflectionParameterNameDiscoverer implements ParameterNameDiscoverer {
    
    

	@Override
	@Nullable
	public String[] getParameterNames(Method method) {
    
    
		return getParameterNames(method.getParameters());
	}

	@Override
	@Nullable
	public String[] getParameterNames(Constructor<?> ctor) {
    
    
		return getParameterNames(ctor.getParameters());
	}

	@Nullable
	private String[] getParameterNames(Parameter[] parameters) {
    
    
		//初始化一个用于存放参数名的数组,长度为parameters的长度
		String[] parameterNames = new String[parameters.length];
		//遍历Parameter对象数组
		for (int i = 0; i < parameters.length; i++) {
    
    
			//获取Parameters中的第i个Parameter对象
			Parameter param = parameters[i];
			//Parameter.isNamePresent:如果参数具有根据类文件的名称,则返回true。否则
			// 		返回false。参数是否具有名称由声明该参数的方法MethodParameters确定。
			//  	简单来说就是验证参数名是不是可用
			if (!param.isNamePresent()) {
    
    
				//返回null,表示获取参数名失败
				return null;
			}
			//获取param的名称赋值给第i个Parameter对象
			parameterNames[i] = param.getName();
		}
		//返回参数名数组
		return parameterNames;
	}

}

LocalVariableTableParameterNameDiscoverer

/**
 * Implementation of {@link ParameterNameDiscoverer} that uses the LocalVariableTable
 * information in the method attributes to discover parameter names. Returns
 * {@code null} if the class file was compiled without debug information.
 * <p>{@link ParameterNameDiscoverer}的实现,该方法使用方法属性中的LocalVariableTable信息
 * 来发现参数名.如果类文件是在没有调试信息的情况下编译的,则返回{@code null}</p>
 * <p>Uses ObjectWeb's ASM library for analyzing class files. Each discoverer instance
 * caches the ASM discovered information for each introspected Class, in a thread-safe
 * manner. It is recommended to reuse ParameterNameDiscoverer instances as far as possible.
 * <p>使用ObjectWeb的ASM库分析类文件。每个发现者实例以线程安全的方式为每个自省类缓存ASM
 * 发现的信息。建议尽可能重用ParameterNameDiscover实例</p>
 * @author Adrian Colyer
 * @author Costin Leau
 * @author Juergen Hoeller
 * @author Chris Beams
 * @author Sam Brannen
 * @since 2.0
 */
public class LocalVariableTableParameterNameDiscoverer implements ParameterNameDiscoverer {
    
    

	/**
	 * 日志类
	 */
	private static final Log logger = LogFactory.getLog(LocalVariableTableParameterNameDiscoverer.class);

	// marker object for classes that do not have any debug info
	/**
	 * 没有任何调试信息的类的标记对象
	 */
	private static final Map<Executable, String[]> NO_DEBUG_INFO_MAP = Collections.emptyMap();

	// the cache uses a nested index (value is a map) to keep the top level cache relatively small in size
	/**
	 * <p> 方法声明类 - (Constructor/Method对象-参数名数组缓存) 线程安全缓存Map</p>
	 * <p>缓存使用嵌套索引(值是一个映射)来使得顶级缓存相对较小</p>
	 */
	private final Map<Class<?>, Map<Executable, String[]>> parameterNamesCache = new ConcurrentHashMap<>(32);


	@Override
	@Nullable
	public String[] getParameterNames(Method method) {
    
    
		//获取提供的桥接方法的原始方法
		Method originalMethod = BridgeMethodResolver.findBridgedMethod(method);
		//获取给定Constructor/Method的参数名数组
		return doGetParameterNames(originalMethod);
	}

	@Override
	@Nullable
	public String[] getParameterNames(Constructor<?> ctor) {
    
    
		return doGetParameterNames(ctor);
	}

	/**
	 * 获取给定Constructor/Method的参数名数组
	 * @param executable Constructor/Method对象
	 * @return 给定Constructor/Method的参数名数组
 	 */
	@Nullable
	private String[] doGetParameterNames(Executable executable) {
    
    
		//获取executable的声明类
		Class<?> declaringClass = executable.getDeclaringClass();
		//获取declaringClass对应的Map<Excecutable,String[]>对象,如果没有,通过inspectClass方法构建一个
		Map<Executable, String[]> map = this.parameterNamesCache.computeIfAbsent(declaringClass, this::inspectClass);
		//如果map不是没有任何调试信息的类的标记对象,就返回在map中对应executable的参数名数组;否则返回null
		return (map != NO_DEBUG_INFO_MAP ? map.get(executable) : null);
	}

	/**
	 * Inspects the target class.
	 * <p>检查目标类</p>
	 * <p>Exceptions will be logged, and a marker map returned to indicate the
	 * lack of debug information.
	 * <p>将记录异常,并返回标记映射以指示调试信息</p>
	 */
	private Map<Executable, String[]> inspectClass(Class<?> clazz) {
    
    
		//获取clazz的class文件流
		InputStream is = clazz.getResourceAsStream(ClassUtils.getClassFileName(clazz));
		//如果文件流为null
		if (is == null) {
    
    
			// We couldn't load the class file, which is not fatal as it
			// simply means this method of discovering parameter names won't work.
			// 我们无法加载类文件,它不是致命的,因为它仅仅意味着发现参数名称的这种方法将行不通。
			//如果是debug模式
			if (logger.isDebugEnabled()) {
    
    
				//log:没有找到类[clazz]的'.class'文件-无法确定构造函数/方法的参数名
				logger.debug("Cannot find '.class' file for class [" + clazz +
						"] - unable to determine constructor/method parameter names");
			}
			//返回没有任何调试信息的类的标记对象
			return NO_DEBUG_INFO_MAP;
		}
		try {
    
    
			//ClassVisitor:访问Java类的访问者
			//ClassReader:用来使{@link ClassVisitor}的解析器访问Java虚拟机规范(JVMS)中的定义的ClassFile结构。此类
			// 解析ClassFile内容,并为遇到的每个字段,方法和字节码调用给定{@link ClassVisitor}的适当访问方法
			ClassReader classReader = new ClassReader(is);
			//初始化一个并发哈希映射,初始化容量为32,用于存储Method/Constructor对象-参数名数组
			Map<Executable, String[]> map = new ConcurrentHashMap<>(32);
			//ParameterNameDiscoveringVisitor:帮助类,它检查所有方法和构造函数,然后尝试查找给定的Executable的参数名
			//ClassReader.accept:使用给定的方法者访问传递给此ClassReader的构造函数的JVMS ClassFile结构。
			classReader.accept(new ParameterNameDiscoveringVisitor(clazz, map), 0);
			//返回用于存储Method/Constructor对象-参数名数组映射
			return map;
		}
		catch (IOException ex) {
    
    
			//捕捉IO异常
			//如果日志级别为DEBUG级别
			if (logger.isDebugEnabled()) {
    
    
				//日志描述:读取类[clazz]的'.class'文件时引发异常-无法确定构造函数/方法参数名称
				logger.debug("Exception thrown while reading '.class' file for class [" + clazz +
						"] - unable to determine constructor/method parameter names", ex);
			}
		}
		catch (IllegalArgumentException ex) {
    
    
			//捕捉非法参数异常
			//如果日志级别为DEBUG级别
			if (logger.isDebugEnabled()) {
    
    
				//日志描述:ASM ClassReader无法解析类文件[clazz],可能是由于尚不支持Java类文件版本
				// -无法确定构造函数/方法参数名称
				logger.debug("ASM ClassReader failed to parse class file [" + clazz +
						"], probably due to a new Java class file version that isn't supported yet " +
						"- unable to determine constructor/method parameter names", ex);
			}
		}
		finally {
    
    
			try {
    
    
				//关闭类流
				is.close();
			}
			catch (IOException ex) {
    
    
				// ignore -- 忽略关闭流是的所有IO异常
			}
		}
		//返回没有任何调试信息的类的标记对象
		return NO_DEBUG_INFO_MAP;
	}


	/**
	 * Helper class that inspects all methods and constructors and then
	 * attempts to find the parameter names for the given {@link Executable}.
	 * <p>帮助类,它检查所有方法和构造函数,然后尝试查找给定的{@link Executable}的
	 * 参数名</p>
	 */
	private static class ParameterNameDiscoveringVisitor extends ClassVisitor {
    
    

		/**
		 * 静态类初始化
		 */
		private static final String STATIC_CLASS_INIT = "<clinit>";

		/**
		 * 方法声明类
		 */
		private final Class<?> clazz;

		/**
		 * 方法-参数名数组映射
		 */
		private final Map<Executable, String[]> executableMap;

		/**
		 * 新建一个{@link ParameterNameDiscoveringVisitor}实例
		 * @param clazz 方法声明类
		 * @param executableMap 方法-参数名数组映射
		 */
		public ParameterNameDiscoveringVisitor(Class<?> clazz, Map<Executable, String[]> executableMap) {
    
    
			//SpringAsmInfo.ASM_VERSION:用于Spring的ASM访问者实现的ASM兼容版本:当前为
			// {@link Opcodes#ASM7},从SpringFramework5.1开始
			super(SpringAsmInfo.ASM_VERSION);
			this.clazz = clazz;
			this.executableMap = executableMap;
		}

		@Override
		@Nullable
		public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
    
    
			// exclude synthetic + bridged && static class initialization
			// 排除合成+桥接 && 静态类初始化
			if (!isSyntheticOrBridged(access) && !STATIC_CLASS_INIT.equals(name)) {
    
    
				return new LocalVariableTableVisitor(this.clazz, this.executableMap, name, desc, isStatic(access));
			}
			return null;
		}

		/**
		 * 根据给定方法的访问标记确定是否是合成或者是桥接方法
		 * @param access 方法的访问标记
		 * @return 如果是合成或者是桥接方法,返回true;否则返回false
		 */
		private static boolean isSyntheticOrBridged(int access) {
    
    
			return (((access & Opcodes.ACC_SYNTHETIC) | (access & Opcodes.ACC_BRIDGE)) > 0);
		}

		/**
		 * 根据给定方法的访问标记确定是否是静态方法
		 * @param access 方法的访问标记
		 * @return  如果是静态方法,返回true;否则返回false
		 */
		private static boolean isStatic(int access) {
    
    
			return ((access & Opcodes.ACC_STATIC) > 0);
		}
	}

	/**
	 * 本地变量表访问器
	 */
	private static class LocalVariableTableVisitor extends MethodVisitor {
    
    

		/**
		 * 构造函数名
		 */
		private static final String CONSTRUCTOR = "<init>";

		/**
		 * 方法声明类
		 */
		private final Class<?> clazz;

		/**
		 * 方法-方法参数名数组
		 */
		private final Map<Executable, String[]> executableMap;

		/**
		 * 方法名
		 */
		private final String name;

		/**
		 * 方法参数对应的{@link org.springframework.asm.Type}
		 */
		private final Type[] args;

		/**
		 * 方法参数名
		 */
		private final String[] parameterNames;

		/**
		 * 是否是静态方法的标记
		 */
		private final boolean isStatic;

		/**
		 * 有lvt信息标记
		 * <p>lVT 就是 LocalVariableTable 缩写,相关文章:https://www.jianshu.com/p/876eaa14a0a9</p>
		 */
		private boolean hasLvtInfo = false;

		/**
		 * The nth entry contains the slot index of the LVT table entry holding the
		 * argument name for the nth parameter.
		 * <p>第n个条目包含LVT表条目的插槽索引,该条目保留第n个参数的参数名称。</p>
		 * <p>lVT 就是 LocalVariableTable 缩写,相关文章:https://www.jianshu.com/p/876eaa14a0a9</p>
		 */
		private final int[] lvtSlotIndex;

		/**
		 *
		 * @param clazz 方法声明类
		 * @param map 方法-方法参数名数组
		 * @param name 方法名
		 * @param desc 方法的描述符(参见{@link Type})
		 * @param isStatic 是否是静态方法
		 */
		public LocalVariableTableVisitor(Class<?> clazz, Map<Executable, String[]> map, String name, String desc, boolean isStatic) {
    
    
			//用于Spring的ASM访问者实现的ASM兼容版本:当前为Opcodes.ASM7,从 SpringFramework5.1开始
			super(SpringAsmInfo.ASM_VERSION);
			this.clazz = clazz;
			this.executableMap = map;
			this.name = name;
			//获取desc的参数类型相对应的Type值
			this.args = Type.getArgumentTypes(desc);
			this.parameterNames = new String[this.args.length];
			this.isStatic = isStatic;
			//计算出lvt插槽指数数组的每个值
			this.lvtSlotIndex = computeLvtSlotIndices(isStatic, this.args);
		}

		@Override
		public void visitLocalVariable(String name, String description, String signature, Label start, Label end, int index) {
    
    
			//当触发该方法,就表示有LocalVariableTable信息,所以设置为true
			this.hasLvtInfo = true;
			//遍历LocalVariableTable插槽索引数组
				for (int i = 0; i < this.lvtSlotIndex.length; i++) {
    
    
					//如果第i个LocalVariableTable插槽索引等于该局部变量的索引
				if (this.lvtSlotIndex[i] == index) {
    
    
					//第i个参数名就为该局部变量名
					this.parameterNames[i] = name;
				}
			}
		}

		@Override
		public void visitEnd() {
    
    
			//如果存在LocalVariableTable的信息 或者 该方法为静态方法且该方法没有参数
			if (this.hasLvtInfo || (this.isStatic && this.parameterNames.length == 0)) {
    
    
				// visitLocalVariable will never be called for static no args methods
				// which doesn't use any local variables.
				// 不会使用任何局部变量的静态无参方法从不调用visitLocalVariable
				// This means that hasLvtInfo could be false for that kind of methods
				// even if the class has local variable info.
				// 这意味着即使类具有局部变量信息,hasLvtInfo对于这种方法也可能为false
				// 解析出Constructor/Method对象,并将其与参数名数组的关系映射添加到
				// 	方法-方法参数名数组映射中
				this.executableMap.put(resolveExecutable(), this.parameterNames);
			}
		}

		/**
		 * 解析出Constructor/Method对象
		 * @return Constructor/Method对象
		 */
		private Executable resolveExecutable() {
    
    
			//获取方法声明类的类加载器
			ClassLoader loader = this.clazz.getClassLoader();
			//初始化参数类型数组,长度为args的长度
			Class<?>[] argTypes = new Class<?>[this.args.length];
			//遍历args
			for (int i = 0; i < this.args.length; i++) {
    
    
				//将第i个arg的全类名解析成Class实例,支持原始类型(如'int')和数组类型名 (如'String[]').
				// 这实际等效于具有相投参数的forName方法,唯一的区别 是在类加载的情况下引发异常
				argTypes[i] = ClassUtils.resolveClassName(this.args[i].getClassName(), loader);
			}
			try {
    
    
				//如果方法名是构造函数名
				if (CONSTRUCTOR.equals(this.name)) {
    
    
					//获取方法声明类中的调用argTypes参数类型数组的Constructor对象并返回出去
					return this.clazz.getDeclaredConstructor(argTypes);
				}
				//到这一步表示获取的是方法,则获取在方法声明类中方法名为name,参数类型数组为
				// argTypes的Method对象并返回出去
				return this.clazz.getDeclaredMethod(this.name, argTypes);
			}
			catch (NoSuchMethodException ex) {
    
    
				//捕捉没有这样方法异常,抛出非法状态异常,异常信息为:方法[this.name]在.class文件中
				// 发现,但无法在class对象中解析
				throw new IllegalStateException("Method [" + this.name +
						"] was discovered in the .class file but cannot be resolved in the class object", ex);
			}
		}

		/**
		 * 计算lvt插槽指数
		 * @param isStatic 是否静态
		 * @param paramTypes 参数类型
		 * @return
		 */
		private static int[] computeLvtSlotIndices(boolean isStatic, Type[] paramTypes) {
    
    
			//lvt插槽指数索引数组
			int[] lvtIndex = new int[paramTypes.length];
			//下一个索引位置,如果是静态就为0,否则为1,因为实例方法,前面第0个位置还有个this
			int nextIndex = (isStatic ? 0 : 1);
			//遍历参数类型数组
			for (int i = 0; i < paramTypes.length; i++) {
    
    
				//设置第i个lvt索引为nextIndex
				lvtIndex[i] = nextIndex;
				//如果参数类型为LONG类型或者是DOUBLE类型,因为如果是long和double需要
				// 2个连续的局部变量表来保存
				if (isWideType(paramTypes[i])) {
    
    
					//nextIndex+2位
					nextIndex += 2;
				}
				else {
    
    
					//nextIndex+1
					nextIndex++;
				}
			}
			//lvt插槽指数索引数组
			return lvtIndex;
		}

		/**
		 * 确定给定的{@link Type}是否为LONG类型或者是DOUBLE类型
		 * @param aType 参数类型
		 * @return 给定的{@link Type}为LONG类型或者是DOUBLE类型时返回true;否则返回false
		 */
		private static boolean isWideType(Type aType) {
    
    
			// float is not a wide type -- float不是宽类型
			return (aType == Type.LONG_TYPE || aType == Type.DOUBLE_TYPE);
		}
	}

}

猜你喜欢

转载自blog.csdn.net/qq_30321211/article/details/108349495