获取java代码中方法的参数名信息

随着java8的使用,在相应的方法签名中增加了新的对象Parameter,用于表示特定的参数信息,通过它的getName可以获取相应的参数名.即像在代码中编写的,如命名为username,那么在前台进行传参时,即不需要再编写如@Parameter("username")类的注解,而直接就能进行按名映射.
如下的代码参考所示:

public class T {
    private interface T2 {
        void method(String username, String password);
    }

    public static void main(String[] args) throws Exception {
        System.out.println(T.class.getMethod("main", String[].class).getParameters()[0].getName());
        System.out.println(T2.class.getMethod("method", String.class, String.class).getParameters()[0].getName());
        System.out.println(T2.class.getMethod("method", String.class, String.class).getParameters()[1].getName());
    }
}

按java8之前,也可以通过一些手段拿到参数名信息,只不过方式不同而已.如通过spring mvc中的ParameterMethodNameResolver在之前的版本中也可以正常工作.不过需要特别的编译而已.这里面起作用的即是 LocalVariableTable 和 MethodParameters,中文编译为本地变量表和方法参数表.

继续阅读“获取java代码中方法的参数名信息”

详细分解classFile常量池(HelloWorld)

当一个java文件被javac编译之后,就可以成为一个通用的class文件格式。我们之前说JVM里面的运行期常量池,主要也就是说的从classFile中读取的常量信息。作为JVM来说,它并没有对类,接口,实例等有一个内部的数据结构,所有的指令的引用信息均来自于常量池中。
Java Virtual Machine instructions do not rely on the run-time layout of classes, interfaces, class instances, or arrays. Instead, instructions refer to symbolic information in the constant_pool table.
本文自:http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html 4.4节

这里,我们有一个很简单的HelloWorld例子,如下所示:

public class T {
    public static void main(String args[]) {
        String s = "abcdefghijk";
        System.out.println(s);
    }
}

采用指令:javac -g:none T.java进行编译。编译之后产生的class如下所示:

Offset     0  1  2  3  4  5  6  7   8  9  A  B  C  D  E  F

00000000   CA FE BA BE 00 00 00 33  00 1A 0A 00 06 00 0C 08     3        
00000010   00 0D 09 00 0E 00 0F 0A  00 10 00 11 07 00 12 07                   
00000020   00 13 01 00 06 3C 69 6E  69 74 3E 01 00 03 28 29        <init>   ()
00000030   56 01 00 04 43 6F 64 65  01 00 04 6D 61 69 6E 01   V   Code   main 
00000040   00 16 28 5B 4C 6A 61 76  61 2F 6C 61 6E 67 2F 53     ([Ljava/lang/S
00000050   74 72 69 6E 67 3B 29 56  0C 00 07 00 08 01 00 0B   tring;)V        
00000060   61 62 63 64 65 66 67 68  69 6A 6B 07 00 14 0C 00   abcdefghijk     
00000070   15 00 16 07 00 17 0C 00  18 00 19 01 00 01 54 01                 T 
00000080   00 10 6A 61 76 61 2F 6C  61 6E 67 2F 4F 62 6A 65     java/lang/Obje
00000090   63 74 01 00 10 6A 61 76  61 2F 6C 61 6E 67 2F 53   ct   java/lang/S
000000A0   79 73 74 65 6D 01 00 03  6F 75 74 01 00 15 4C 6A   ystem   out   Lj
000000B0   61 76 61 2F 69 6F 2F 50  72 69 6E 74 53 74 72 65   ava/io/PrintStre
000000C0   61 6D 3B 01 00 13 6A 61  76 61 2F 69 6F 2F 50 72   am;   java/io/Pr
000000D0   69 6E 74 53 74 72 65 61  6D 01 00 07 70 72 69 6E   intStream   prin
000000E0   74 6C 6E 01 00 15 28 4C  6A 61 76 61 2F 6C 61 6E   tln   (Ljava/lan
000000F0   67 2F 53 74 72 69 6E 67  3B 29 56 00 21 00 05 00   g/String;)V !   
00000100   06 00 00 00 00 00 02 00  01 00 07 00 08 00 01 00                   
00000110   09 00 00 00 11 00 01 00  01 00 00 00 05 2A B7 00                *?
00000120   01 B1 00 00 00 00 00 09  00 0A 00 0B 00 01 00 09    ?             
00000130   00 00 00 17 00 02 00 02  00 00 00 0B 12 02 4C B2                 L?
00000140   00 03 2B B6 00 04 B1 00  00 00 00 00 00                   +? ?     

本文是描述如何从这个classFile中详细的找出相应的常量池信息,从文件本身描述的信息中手动地找出相应的内部结构,以方便进一步掌握class的结构形式,以方便了解JVM规范及组织。

继续阅读“详细分解classFile常量池(HelloWorld)”

读取指定jar所在的系统目录(windows系统中)

在做有关jna的项目开发时,我们经常碰到的问题就是如何去加载我们所写的dll文件。一般来说,这个dll会被放到windows/system32目录下,但这个方法需要手动地将这个dll复制到相应的目录中。但如果这个操作要由用户来做的话,过程就复杂了,不能期望用户总是能按指定的步骤去进行。所以,我们需要一个更方便的方法,比如直接将dll放到与jar相同的目录中,直接放到一起,避免了再重新复制dll的步骤。

使用这个方法,我们就可以使用以下方法来加载这个dll。

System.load(filePath);

这个filePath就是dll的文件路径了。那么问题就剩下如何来找到这个dll了。再简单一点,我们只需要找到这个相绑定的jar的目录就可以了。那么问题就简单了,使用以下方法就可以做到了(这个方法引自JRegistry,一个访问windows注册表的jar工具):  

                String resourceName = X.class.getSimpleName() + ".class";//这里的X就是与dll相绑定的jar中任意一个类
		URL url = X.class.getResource(resourceName);//取得这个class文件的URL
		String urlStr = url.toString();//返回格式为jar:file:/x:/x/xx/xx.jar!/xx/xx/X.class,要求class是存放在jar文件中,如果是文件目录中,则是file:/x:/xx/x.jar!/xx/xx/X.class的格式
		int start = "jar:file:/".length();
		int end = urlStr.indexOf("!/");
		String fileName = urlStr.substring(start, end);将jar:file:/和后面的!/截取掉,就只剩下x:/x/xx/x.jar,就是jar文件的路径名
		File file = new File(fileName);
		System.out.println(file.getParentFile().getCanonicalPath());//直接返回jar文件所在的目录,这个目录就是我们所需要找的目录