溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Java中怎么獲取方法參數(shù)

發(fā)布時(shí)間:2021-07-23 16:49:03 來源:億速云 閱讀:706 作者:Leah 欄目:編程語言

這篇文章將為大家詳細(xì)講解有關(guān)Java中怎么獲取方法參數(shù),文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個(gè)參考,希望大家閱讀完這篇文章后對(duì)相關(guān)知識(shí)有一定的了解。

如果你的項(xiàng)目是實(shí)用maven構(gòu)建,那么就可以加入幾行配置,追加參數(shù)。

<plugin>       <artifactId>maven-compiler-plugin</artifactId>       <version>3.8.0</version>       <configuration>           <source>1.8</source>           <target>1.8</target>           <encoding>utf8</encoding>           <compilerArgs>               <arg>-parameters</arg>           </compilerArgs>       </configuration>   </plugin>

如果是用的IDEA等編輯器,也可以通過設(shè)置界面進(jìn)行配置。不過不推薦這樣,因?yàn)槟愕倪@些配置不好進(jìn)行共享。

Java中怎么獲取方法參數(shù)

在普通Java項(xiàng)目里,就可以通過下面的方式來獲取反射數(shù)據(jù)。Method.getParameters這個(gè)方法是新加的。

public class Test {        public static void main(String[] args) throws Exception{         Class clazz = Class.forName("com.test.MethodParameterTest");         Method[] methods = clazz.getMethods();         Constructor[] constructors = clazz.getConstructors();         for (Constructor constructor : constructors) {             System.out.println("+++" + constructor.getName());             Parameter[] parameters = constructor.getParameters();             for (Parameter parameter : parameters) {                 printParameter(parameter);             }         }            System.out.println("------------------");         for (Method method : methods) {             System.out.println(method.getName());             Parameter[] parameters = method.getParameters();             for (Parameter parameter : parameters) {                 printParameter(parameter);             }         }     }        private static void printParameter(Parameter parameter) {         //參數(shù)名         System.out.println("\t\t" + parameter.getName());         //是否在源碼中隱式聲明的參數(shù)名         System.out.println("\t\t\t implicit:" + parameter.isImplicit());         //類文件中,是否存在參數(shù)名         System.out.println("\t\t\t namePresent:" + parameter.isNamePresent());         //是否為虛構(gòu)參數(shù)         System.out.println("\t\t\t synthetic:" + parameter.isSynthetic());         System.out.println("\t\t\t VarArgs:" + parameter.isVarArgs());     } }

下面介紹幾個(gè)方法的意義:

isImplicit()

參數(shù)是否為隱式聲明在源文件中,比如內(nèi)部類,默認(rèn)構(gòu)造函數(shù)(無參)其實(shí)在編譯成class時(shí)將會(huì)把包含它的主類引用作為首個(gè)參數(shù),此參數(shù)即為隱式聲明。

如果為true,即表示有JDK編譯器隱式生成在class文件中的方法參數(shù),而source文件中并不可見。常規(guī)的普通方法,此值為false。

isNamePresent()

此參數(shù)在class文件中是否有此參數(shù)名;受制于在編譯時(shí)是否指定了“-parameter”,對(duì)于指定此參數(shù)的編譯文件,通常為true;對(duì)于JDK  內(nèi)部類、默認(rèn)編譯的類,通常為false;此時(shí)你會(huì)發(fā)現(xiàn),它們的參數(shù)名通常為表意名稱:arg0、arg1等等,此時(shí)為false。

isSynthetic()

是否為“虛構(gòu)”參數(shù),如果為true,表示既不是“顯式”聲明、也不是隱式聲明在源文件中的參數(shù),比如enum類的“values()”、“valueOf(String)”這是編譯器“虛構(gòu)”的系統(tǒng)方法。

在Spring環(huán)境中,由于有工具類的支持,會(huì)更加方便一些。

public class SpringTest {        private static final ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();           public static void main(String[] args) throws Exception{         Class clazz = Class.forName("com.test.MethodParameterTest");         Method[] methods = clazz.getMethods();         for (Method method : methods) {             System.out.println(method.getName());             //JDK 1.8 + is better.             String[] parameterNames = parameterNameDiscoverer.getParameterNames(method);             if (parameterNames == null) {                 continue;             }             for (String pn : parameterNames) {                 System.out.println("\t\t" + pn);             }         }     } }

那Java版本低于1.8的時(shí)候,又是怎么獲取的呢?我們可以參考Spring的LocalVariableTableParameterNameDiscoverer類。

public String[] getParameterNames(Method method) {         Method originalMethod = BridgeMethodResolver.findBridgedMethod(method);         return doGetParameterNames(originalMethod); } @Nullable private String[] doGetParameterNames(Executable executable) {         Class<?> declaringClass = executable.getDeclaringClass();         Map<Executable, String[]> map = this.parameterNamesCache.computeIfAbsent(declaringClass, this::inspectClass);         return (map != NO_DEBUG_INFO_MAP ? map.get(executable) : null); }

最后就走到了inspectClass方法中。

private Map<Executable, String[]> inspectClass(Class<?> clazz) {         InputStream is = clazz.getResourceAsStream(ClassUtils.getClassFileName(clazz));         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.             if (logger.isDebugEnabled()) {                 logger.debug("Cannot find '.class' file for class [" + clazz +                         "] - unable to determine constructor/method parameter names");             }             return NO_DEBUG_INFO_MAP;         }         try {             ClassReader classReader = new ClassReader(is);             Map<Executable, String[]> map = new ConcurrentHashMap<>(32);             classReader.accept(new ParameterNameDiscoveringVisitor(clazz, map), 0);             return map;         }         ...

可以看到,這種情況下,Spring是通過直接讀取class文件進(jìn)行解析的。實(shí)際上是通過讀取LocalVariableTable中的數(shù)據(jù)進(jìn)行獲取的。如果你編譯的時(shí)候沒有加入這些debug選項(xiàng),同樣也拿不到方法參數(shù)的具體名稱。

總結(jié)一下

  • Java8以前,讀取Class中的LocalVariableTable屬性表,需要編譯時(shí)加入?yún)?shù)-g或者-g:vars  獲取方法局部變量調(diào)試信息;

  • Java8及其以后,通過java.lang.reflect.Parameter#getName即可獲取,但需要編譯時(shí)加入?yún)?shù)-parameters參數(shù)。

關(guān)于Java中怎么獲取方法參數(shù)就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI