??xml version="1.0" encoding="utf-8" standalone="yes"?> www.bitsCN.com YOUR_LIB=your_path for jar in `ls $YOUR_LIB/*.jar`
~译HelloWorldc?br>
2 public native void displayHelloWorld();
3
4 public native void printxx(String str);
5
6 static {
7 System.loadLibrary("hello");
8 // System.load("hello");
9 }
10
11 public static void main(String[] args) {
12 HelloWorld hw = new HelloWorld();
13 hw.displayHelloWorld();
14 for (int i = 0;; ++i) {
15 hw
16 .printxx("wo kaowo kaowo kaowo kaowo kaowo kaowo kaowo kaowo kaowo kaowo kao");
17 if (i % 1000 == 0) {
18 try {
19 Thread.sleep(10);
20 } catch (InterruptedException e) {
21 }
22 }
23 }
24 }
25 }
对编译完的class执行
javah HelloWorld
2 #include <jni.h>
3 /* Header for class HelloWorld */
4
5 #ifndef _Included_HelloWorld
6 #define _Included_HelloWorld
7 #ifdef __cplusplus
8 extern "C" {
9 #endif
10 /*
11 * Class: HelloWorld
12 * Method: displayHelloWorld
13 * Signature: ()V
14 */
15 JNIEXPORT void JNICALL Java_HelloWorld_displayHelloWorld
16 (JNIEnv *, jobject);
17
18 /*
19 * Class: HelloWorld
20 * Method: printxx
21 * Signature: (Ljava/lang/String;)V
22 */
23 JNIEXPORT void JNICALL Java_HelloWorld_printxx
24 (JNIEnv *, jobject, jstring);
25
26 #ifdef __cplusplus
27 }
28 #endif
29 #endif
30
~译
cl -I%java_home%\include -I%java_home%\include\win32 -LDHelloWorld.c -Fehello.dll
2 #include "HelloWorld.h"
3 #include <stdio.h>
4 JNIEXPORT void JNICALL Java_HelloWorld_displayHelloWorld(JNIEnv *env, jobject obj)
5 {
6 printf("Hello world!\n");
7 return;
8 }
9
10 JNIEXPORT void JNICALL Java_HelloWorld_printxx
11 (JNIEnv *env, jobject obj, jstring prompt){
12
13 const char *str = (*env)->GetStringUTFChars(env, prompt, 0);
14 printf("%s",prompt);
15 (*env)->ReleaseStringUTFChars(env, prompt, str);
16
17 return;
18 }
19
20
3QJavacd和本地类型对?br>
在如下情况下Q需要在本地Ҏ(gu)中应用java对象的引用,׃(x)用到cd之间的{换:(x)
1QjavaҎ(gu)里面参C入本地方法;
2Q在本地Ҏ(gu)里面创徏java对象Q?br>
3Q在本地Ҏ(gu)里面returnl果ljavaE序?br>
分ؓ(f)如下两种情况Q?br>
Java原始cd
像booleans、integers、floats{从JavaE序中传到本地方法中的原始类型可以直接用,下面是java中的原始cd和本地方法中的类型的对应Q?br>
Javacd 本地cd 字节(bit)
boolean jboolean 8, unsigned
byte jbyte 8
char jchar 16, unsigned
short jshort 16
int jint 32
long jlong 64
float jfloat 32
double jdouble 64
void void n/a
也就是说如果我在Ҏ(gu)中传q去?jin)一个boolean的参数的话,那么我在本地Ҏ(gu)中就有jbooleancd与之对应。同理,如果在本地方法中return一个jint的话Q那么在java中就q回一个intcd?中国|管论坛
Java对象
Java对象做ؓ(f)引用被传递到本地Ҏ(gu)中,所有这些Java对象的引用都有一个共同的父类型jobject(相当于java中的ObjectcL所有类的父cM?。下面是JNI实现的一些jobject的子c:(x)
4Q本地方法中讉KjavaE序中的内容
1)讉KString对象Q?br>
从javaE序中传q去的String对象在本地方法中对应的是jstringcdQjstringcd和c中的char*不同Q所以如果你直接当做char*使用的话Q就?x)出错。因此在使用之前需要将jstring转换成ؓ(f)c/c++中的char*Q这里用JNIEnv的方法{换。下面是一个例子:(x)
代码3Q?br>
JNIEXPORT jstring JNICALL Java_Prompt_getLine
(JNIEnv *env, jobject obj, jstring prompt)
{
char buf[128];
const char *str = (*env)->GetStringUTFChars(env, prompt, 0);
printf("%s", str);
(*env)->ReleaseStringUTFChars(env, prompt, str);
q里使用GetStringUTFCharsҎ(gu)传q来的promptQjstringcdQ{换成为UTFQ?的格式,p够在本地Ҏ(gu)中用了(jin)?br>
注意Q在使用完你所转换之后的对象之后,需要显C用ReleaseStringUTFCharsҎ(gu)Q让JVM释放转换成UTF-8的string的对象的I间Q如果不昄的调用的话,JVM中会(x)一直保存该对象Q不?x)被垃圾回收器回Ӟ因此׃?x)D内存溢出?
下面是访问String的一些方法:(x)
◆GetStringUTFCharsjstring转换成ؓ(f)UTF-8格式的char*
◆GetStringCharsjstring转换成ؓ(f)Unicode格式的char*
◆ReleaseStringUTFChars释放指向UTF-8格式的char*的指?br>
◆ReleaseStringChars释放指向Unicode格式的char*的指?br>
◆NewStringUTF创徏一个UTF-8格式的String对象
◆NewString创徏一个Unicode格式的String对象
◆GetStringUTFLengt获取UTF-8格式的char*的长?br>
◆GetStringLength获取Unicode格式的char*的长?br>
2) 讉KArray对象Q?br>
和String对象一P在本地方法中不能直接讉Kjarray对象Q而是使用JNIEnv指针指向的一些方法来是用?br>
讉KJava原始cd数组Q?br>
1Q获取数l的长度Q?br>
代码4Q?br>
JNIEXPORT jint JNICALL Java_IntArray_sumArray
(JNIEnv *env, jobject obj, jintArray arr)
{
int i, sum = 0;
jsize len = (*env)->GetArrayLength(env, arr);
如代?所C,q里获取数组的长度和普通的c语言中的获取数组长度不一Pq里使用JNIEvn的一个函数GetArrayLength?
2Q获取一个指向数l元素的指针Q?br>
代码4Q?br>
jint *body = (*env)->GetIntArrayElements(env, arr, 0);
使用GetIntArrayElementsҎ(gu)获取指向arr数组元素的指针,注意该函数的参数Q第一个是JNIEnvQ第二个是数l,W三个是数组里面W三个是数组里面开始的元素
3Q用指针取出Array中的元素
代码5Q?br>
for (i=0; i<len; i++) {
sum += body[i];
}
q里使用和普通的c中的数组使用没有什么不同了(jin)
4Q释放数l元素的引用
代码6Q?br>
(*env)->ReleaseIntArrayElements(env, arr, body, 0);
和操作String中的释放String的引用是一L(fng)Q提醒JVM回收arr数组元素的引用?br>
q里丄例子是用int数组的,同样q有boolean、float{对应的数组?br>
获取数组元素指针的对应关p:(x)
函数 数组cd
GetBooleanArrayElements boolean
GetByteArrayElements byte
GetCharArrayElements char bitsCN.nET中国|管博客
GetShortArrayElements short
GetIntArrayElements int
GetLongArrayElements long
GetFloatArrayElements float
GetDoubleArrayElements double
释放数组元素指针的对应关p:(x)
Function Array Type
ReleaseBooleanArrayElements boolean
ReleaseByteArrayElements byte
ReleaseCharArrayElements char
ReleaseShortArrayElements short
ReleaseIntArrayElements int
ReleaseLongArrayElements long
ReleaseFloatArrayElements float
ReleaseDoubleArrayElements double
讉K自定义Java对象数组
The JNI provides a separate set of functions to access elements of object arrays. You can use these functions to get and set individual object array elements.
Note: You cannot get all the object array elements at once.
GetObjectArrayElement returns the object element at a given index.
SetObjectArrayElement updates the object element at a given index.
3) 讉KJava对象的方法:(x)
在本地方法中调用Java对象的方法的步骤Q?br>
?获取你需要访问的Java对象的类Q?br>
jclass cls = (*env)->GetObjectClass(env, obj);
使用GetObjectClassҎ(gu)获取obj对应的jclass?br>
?获取MethodIDQ?br>
jmethodID mid = (*env)->GetMethodID(env, cls, "callback", "(I)V");
使用GetMethdoIDҎ(gu)获取你要使用的方法的MethdoID。其参数的意义:(x)
env??>JNIEnv
cls??>W一步获取的jclass
"callback"??>要调用的Ҏ(gu)?br>
"(I)V"??>Ҏ(gu)的Signature
?调用Ҏ(gu)Q?br>
(*env)->CallVoidMethod(env, obj, mid, depth);
使用CallVoidMethodҎ(gu)调用Ҏ(gu)。参数的意义Q?br>
env??>JNIEnv
obj??>通过本地Ҏ(gu)I过来的jobject
mid??>要调用的MethodIDQ即W二步获得的MethodIDQ?br>
depth??>Ҏ(gu)需要的参数Q对应方法的需求,d相应的参敎ͼ(j) bitsCN.nET中国|管博客
注:(x)q里使用的是CallVoidMethodҎ(gu)调用Q因为没有返回|如果有返回值的话用对应的Ҏ(gu)Q在后面?x)提到?br>
Ҏ(gu)的Signature
Ҏ(gu)的Signature是由Ҏ(gu)的参数和q回值的cd共同构成的,下面是他们的l构Q?br>
"(argument-types)return-type"
其中JavaE序中参数类型和其对应的值如下:(x)
Signature Java中的cd
Z boolean
B byte
C char
S short
I int
J long
F float
D double
L fully-qualified-class; fully-qualified-class
[ type type[]
( arg-types ) ret-type method type
一个JavacȝҎ(gu)的Signature可以通过javap命o(h)获取Q?br>
javap -s -p Javacd
l调用的函数传参敎ͼ(x)
通常我们直接在methodID后面要传的参数d在后面,但是q有其他的方法也可以传参敎ͼ(x)
CallVoidMethodV可以获取一个数量可变的列表作ؓ(f)参数Q?www_bitscn_com
CallVoidMethodA可以获取一个union?br>
调用?rn)态方法:(x)
是第二步和第三步调用的方法改为对应的Q?br>
GetStaticMethodID获取对应的静(rn)态方法的ID
CallStaticIntMethod调用?rn)态方?br>
调用类的方法:(x)
用的比较?yu),自己看啦。^_^?br>
4)讉KJava对象的属性:(x)
讉KJava对象的属性和讉KJava对象的方法基本上一P只需要将函数里面的Method改ؓ(f)Field卛_
]]>
do
CLASSPATH="$CLASSPATH:""$jar"
done
windows :
SETLOCAL ENABLEDELAYEDEXPANSION
set LIB=xx
set CLASSPATH=.
FOR %%C IN (LIB\*.jar) DO set CLASSPATH=!CLASSPATH!;%%C
echo %CLASSPATH%
unix ksh:
暂无
]]>
(tng)
1.4.2jdk~译执行。长旉执行没有发现有网上所说的׃jit优化D的当分配完Foo的内存,Foo构造函数未初始化完成就其地址赋值给foo的错误。相信这时候jit已经对代码进行了(jin)优化?br />
国外|址关于Double-Checked Locking的文?a >http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
Paul Jakubik found an example of a use of double-checked locking that did not work correctly. A slightly cleaned up version of that code is available here.
When run on a system using the Symantec JIT, it doesn't work. In particular, the Symantec JIT compiles
singletons[i].reference = new Singleton();
to the following (note that the Symantec JIT using a handle-based object allocation system).
0206106A mov eax,0F97E78h 0206106F call 01F6B210 ; allocate space for ; Singleton, return result in eax 02061074 mov dword ptr [ebp],eax ; EBP is &singletons[i].reference ; store the unconstructed object here. 02061077 mov ecx,dword ptr [eax] ; dereference the handle to ; get the raw pointer 02061079 mov dword ptr [ecx],100h ; Next 4 lines are 0206107F mov dword ptr [ecx+4],200h ; Singleton's inlined constructor 02061086 mov dword ptr [ecx+8],400h 0206108D mov dword ptr [ecx+0Ch],0F84030h
As you can see, the assignment to singletons[i].reference is performed before the constructor for Singleton is called. This is completely legal under the existing Java memory model, and also legal in C and C++ (since neither of them have a memory model).
上面是国外网站给出的jit代码和说明?br />
import org.apache.bcel.Constants;
import org.apache.bcel.classfile.ClassParser;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.classfile.Method;
import org.apache.bcel.generic.ClassGen;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.InstructionConstants;
import org.apache.bcel.generic.InstructionFactory;
import org.apache.bcel.generic.InstructionList;
import org.apache.bcel.generic.MethodGen;
import org.apache.bcel.generic.ObjectType;
import org.apache.bcel.generic.PUSH;
import org.apache.bcel.generic.Type;
public class BCELTiming {
(tng) (tng) (tng) /**
(tng) (tng) (tng) (tng) * Add timing wrapper to method of class. The method can accept any
(tng) (tng) (tng) (tng) * arguments and return any type (including void), but must be a normal
(tng) (tng) (tng) (tng) * (non-static, non-initializer) method to be used with this code as
(tng) (tng) (tng) (tng) * currently implemented. Handling the other types of methods would not
(tng) (tng) (tng) (tng) * involve any fundamental changes to the code.
(tng) (tng) (tng) (tng) *
(tng) (tng) (tng) (tng) * @param cgen
(tng) (tng) (tng) (tng) * (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) generator for class being modified
(tng) (tng) (tng) (tng) * @param method
(tng) (tng) (tng) (tng) * (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) current method to be enhanced with timing wrapper
(tng) (tng) (tng) (tng) */
(tng) (tng) (tng) private static void addWrapper(ClassGen cgen, Method method) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) // set up the construction tools
(tng) (tng) (tng) (tng) (tng) (tng) (tng) InstructionFactory ifact = new InstructionFactory(cgen);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) InstructionList ilist = new InstructionList();
(tng) (tng) (tng) (tng) (tng) (tng) (tng) ConstantPoolGen pgen = cgen.getConstantPool();
(tng) (tng) (tng) (tng) (tng) (tng) (tng) String cname = cgen.getClassName();
(tng) (tng) (tng) (tng) (tng) (tng) (tng) MethodGen wrapgen = new MethodGen(method, cname, pgen);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) wrapgen.setInstructionList(ilist);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) // rename a copy of the original method
(tng) (tng) (tng) (tng) (tng) (tng) (tng) MethodGen methgen = new MethodGen(method, cname, pgen);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) cgen.removeMethod(method);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) String iname = methgen.getName() + "$impl";
(tng) (tng) (tng) (tng) (tng) (tng) (tng) methgen.setName(iname);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) cgen.addMethod(methgen.getMethod());
(tng) (tng) (tng) (tng) (tng) (tng) (tng) //以上是一下初始化的工?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) // compute the size of the calling parameters
(tng) (tng) (tng) (tng) (tng) (tng) (tng) // operand stack操作数堆?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) Type[] types = methgen.getArgumentTypes(); // 取出参数cd数组
(tng) (tng) (tng) (tng) (tng) (tng) (tng) // solt代表本地变量的堆栈偏U量,里头储存?sh)(jin)调用methen代表的函数的参数
(tng) (tng) (tng) (tng) (tng) (tng) (tng) int slot = methgen.isStatic() ? 0 : 1; // q种方式与Java如何处理Ҏ(gu)调用有关。对于非?rn)态的Ҏ(gu)Q每ơ调用的W一个(隐藏的)(j)参数是目标对象的this引用Q就是位|?储存的内容)(j)?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) for (int i = 0; i < types.length; i++) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) slot += types[i].getSize();// 累计个个参数cd的长度,
(tng) (tng) (tng) (tng) (tng) (tng) (tng) }
(tng) (tng) (tng) (tng) (tng) (tng) (tng) // 现在solt指向最后一个参数的下一个位|?/p>
(tng) (tng) (tng) (tng) (tng) (tng) (tng) // save time prior to invocation
(tng) (tng) (tng) (tng) (tng) (tng) (tng) // 调用?rn)态的long java.lang.System.currentTimeMillis()Ҏ(gu),调用l束后函数的q回的longcd的g(x)压入operand stack操作数堆?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) ilist.append(ifact.createInvoke("java.lang.System",
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) "currentTimeMillis", Type.LONG, Type.NO_ARGS,
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) Constants.INVOKESTATIC));
(tng) (tng) (tng) (tng) (tng) (tng) (tng) ilist.append(InstructionFactory.createStore(Type.LONG, slot));// operand stack的top保存到本地变量堆栈的slot位置,operand stack弹出long?/p>
(tng) (tng) (tng) (tng) (tng) (tng) (tng) // call the wrapped method
(tng) (tng) (tng) (tng) (tng) (tng) (tng) int offset = 0; // 偏移?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) short invoke = Constants.INVOKESTATIC; // 预先讄用静(rn)态函?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) if (!methgen.isStatic()) { // 如果不是调用?rn)态函?调用的W一个(隐藏的)(j)参数(目标对象的this引用)压入operand stack
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) ilist.append(InstructionFactory.createLoad(Type.OBJECT, 0));
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) offset = 1;// 偏移量加1
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) invoke = Constants.INVOKEVIRTUAL;// 讄用非?rn)态函?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) }
(tng) (tng) (tng) (tng) (tng) (tng) (tng) for (int i = 0; i < types.length; i++) { // 遍历所有参?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) Type type = types[i];
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) ilist.append(InstructionFactory.createLoad(type, offset)); // 按参数类型把参数一个个从本地变量堆栈取出,压入operand stack
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) offset += type.getSize();
(tng) (tng) (tng) (tng) (tng) (tng) (tng) }
(tng) (tng) (tng) (tng) (tng) (tng) (tng) Type result = methgen.getReturnType();// 取得要调用函数的q回值类?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) ilist.append(ifact.createInvoke(cname, iname, result, types, invoke));// 调用Ҏ(gu)名ؓ(f)iname的函?/p>
(tng) (tng) (tng) (tng) (tng) (tng) (tng) // store result for return later
(tng) (tng) (tng) (tng) (tng) (tng) (tng) if (result != Type.VOID) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) ilist.append(InstructionFactory.createStore(result, slot + 2)); // 名为iname的函数返回值复制到本地变量堆栈的slot+2的位|上
(tng) (tng) (tng) (tng) (tng) (tng) (tng) }
(tng) (tng) (tng) (tng) (tng) (tng) (tng) // print time required for method call
(tng) (tng) (tng) (tng) (tng) (tng) (tng) // 获取?rn)态对象java.lang.System.out的引?q回值压入operand stack
(tng) (tng) (tng) (tng) (tng) (tng) (tng) ilist.append(ifact.createFieldAccess("java.lang.System", "out",
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) new ObjectType("java.io.PrintStream"), Constants.GETSTATIC));
(tng) (tng) (tng) (tng) (tng) (tng) (tng) ilist.append(InstructionConstants.DUP);// 取operand stack的top,压入operand stack。完成后load_stack的头两个元素是静(rn)态对象java.lang.System.out的引?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) ilist.append(InstructionConstants.DUP);// 取operand stack的top,压入operand stack。现在有3个java.lang.System.out的引用。供下面3ơ调用out.print()函数使用
(tng) (tng) (tng) (tng) (tng) (tng) (tng) String text = "Call to method " + methgen.getName() + " took ";
(tng) (tng) (tng) (tng) (tng) (tng) (tng) ilist.append(new PUSH(pgen, text));// text攑օpgenQ代表常量池Q?q把其在pgen的引用压入operand stack(供out.print(Sting)调用的参?
(tng) (tng) (tng) (tng) (tng) (tng) (tng) ilist.append(ifact.createInvoke("java.io.PrintStream", "print",
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) Type.VOID, new Type[] { Type.STRING },
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) Constants.INVOKEVIRTUAL));// 调用l束Qoperand stack弹出一个String的引用和一个out的引?q剩2个out),函数没有q回?/p>
(tng) (tng) (tng) (tng) (tng) (tng) (tng) ilist.append(ifact.createInvoke("java.lang.System",
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) "currentTimeMillis", Type.LONG, Type.NO_ARGS,
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) Constants.INVOKESTATIC));// 调用java.lang.System.currentTimeMillis()Ҏ(gu),调用l束后函数的q回的longcd的g(x)压入堆栈operand stack
(tng) (tng) (tng) (tng) (tng) (tng) (tng) ilist.append(InstructionFactory.createLoad(Type.LONG, slot));// 从本地变量堆栈的slot位置载入先前储存的long|压入operand stack
(tng) (tng) (tng) (tng) (tng) (tng) (tng) ilist.append(InstructionConstants.LSUB);// 调用long的减法指?弹出2个long|q把l果压入operand stack,现在operand stack的topW一个是longQ第二个是out的引?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) ilist.append(ifact.createInvoke("java.io.PrintStream", "print",
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) Type.VOID, new Type[] { Type.LONG }, Constants.INVOKEVIRTUAL));// 调用out.print(long)Ҏ(gu)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) ilist.append(new PUSH(pgen, " ms."));// String对象" ms."攑օpgen,q把其在pgen的引用压入operand stack(供out.print(Sting)调用的参?
(tng) (tng) (tng) (tng) (tng) (tng) (tng) ilist
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) .append(ifact.createInvoke("java.io.PrintStream", "println",
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) Type.VOID, new Type[] { Type.STRING },
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) Constants.INVOKEVIRTUAL));
(tng) (tng) (tng) (tng) (tng) (tng) (tng) // return result from wrapped method call
(tng) (tng) (tng) (tng) (tng) (tng) (tng) if (result != Type.VOID) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) ilist.append(InstructionFactory.createLoad(result, slot + 2));// 处理q回?如果不ؓ(f)I,从本地对象堆栈的slot+2位置d指定cd的返回值压入operand stack
(tng) (tng) (tng) (tng) (tng) (tng) (tng) }
(tng) (tng) (tng) (tng) (tng) (tng) (tng) ilist.append(InstructionFactory.createReturn(result)); //调用处理q回值的指o(h)Qresult回值的cd
(tng) (tng) (tng) (tng) (tng) (tng) (tng) //下面是一下扫ַ?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) // finalize the constructed method
(tng) (tng) (tng) (tng) (tng) (tng) (tng) wrapgen.stripAttributes(true);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) wrapgen.setMaxStack();
(tng) (tng) (tng) (tng) (tng) (tng) (tng) wrapgen.setMaxLocals();
(tng) (tng) (tng) (tng) (tng) (tng) (tng) cgen.addMethod(wrapgen.getMethod());
(tng) (tng) (tng) (tng) (tng) (tng) (tng) ilist.dispose();
(tng) (tng) (tng) }
(tng) (tng) (tng) public static void main(String[] argv) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) if (argv.length == 2 && argv[0].endsWith(".class")) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) try {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) JavaClass jclas = new ClassParser(argv[0]).parse();
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) ClassGen cgen = new ClassGen(jclas);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) Method[] methods = jclas.getMethods();
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) int index;
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) for (index = 0; index < methods.length; index++) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) if (methods[index].getName().equals(argv[1])) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) break;
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) }
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) }
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) if (index < methods.length) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) addWrapper(cgen, methods[index]);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) FileOutputStream fos = new FileOutputStream(argv[0]);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) cgen.getJavaClass().dump(fos);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) fos.close();
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) } else {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) System.err.println("Method " + argv[1] + " not found in "
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) + argv[0]);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) }
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) } catch (IOException ex) {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) ex.printStackTrace(System.err);
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) }
(tng) (tng) (tng) (tng) (tng) (tng) (tng) } else {
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) System.out.println("Usage: BCELTiming class-file method-name");
(tng) (tng) (tng) (tng) (tng) (tng) (tng) }
(tng) (tng) (tng) }
}
相对javassistQbcel实比较复杂。但是bcell我的感觉比较自由,有种一切尽在掌握的感觉Q这一Ҏ(gu)较我喜欢?br />虽然自由Q但是用bcel写一个类的实现绝对不?x)是一件让人开?j)的事情Q如果碰巧你的实现又E微复杂?jin)?比如实现?jin)xx接口Q又增加?jin)一些函数和成员变量)。而且你的实现未必?x)比javac~译出来的代码效率高Q不考虑jvm的动态优化)(j)?br />不过Q先把你要实现的cȝ代码写出来,按照代码来写bcel的实玎ͼ?x)降低些实现隑ֺ?/p>