Did you have to
disassemble the expression ? To draw a graph of the function on the line entered by the user?
Agree, the occupation brings more headaches than the joy of the result. Perhaps you are familiar with the
antlr or
javacc libraries , then you will get
rid of a little blood. But acquire the tail of ugly generated classes, which as soon as possible hide from prying eyes in the farthest package.
Having written
yesterday about cglib , I noticed in the documentation a chapter on bytecode modification. And by itself, the question arises, is it possible at runtime to force the class to perform, what it really wants, and not what the class wants?
')
I honestly took up the study of documentation and quickly went to the popular bym-code editor
asm . However, to my disappointment, modifying the byte-code can only be quite good knowing and understanding it. More precisely, this means that if you need to return the result of executing “x * x + x / 2”, you must compile this expression in the statement.
Not wanting to write a compiler, I still formulated a request for google and found what
I was looking for.To my luck, a similar compiler is already implemented in another
javassist bytecode editor. By the way, javassist is more documented, however in the open-source community there is an opinion that cglib is much faster. In our case, the speed of creating a class is not as important as the speed of its methods. So, what needs to be done:
Copy Source | Copy HTML public interface Evaluator { public double eval( double x); }
Copy Source | Copy HTML public interface Evaluator { public double eval( double x); }
Copy Source | Copy HTML public interface Evaluator { public double eval( double x); }
Copy Source | Copy HTML public interface Evaluator { public double eval( double x); }
Class creation:
Copy Source | Copy HTML
- ClassPool pool = ClassPool.getDefault ();
- CtClass evalClass = pool.makeClass ( "Formula" );
- evalClass.setInterfaces (
- new CtClass [] {
- pool.makeClass ( "com.micro.bench.Evaluator" )
- });
- String expession = "x * x + x / 2" ;
- evalClass.addMethod (
- CtNewMethod.make (
- "public double eval (double x) {return (" + expession + ");}" ,
- evalClass));
- Class clazz = evalClass.toClass ();
- runtime = (Evaluator) clazz.newInstance ();
Everything! In our hands, a class object that implements the Evaluator interface, which will return x * x + x / 2 to us
Well, now it would not be bad to compare performance. Thanks to
TheShade for the
comment , I modified Timer a bit and used it for testing. A test result showing that both methods run at the same time:
total | amount | last | last 5 | last 10 | avg | dev | operation
6856.00 | 20.00 | 351.00 | 343.00 | 341.00 | 342.80 | 1.24 | .. runtime calc
6874.00 | 20.00 | 337.00 | 343.00 | 344.00 | 343.70 | 1.03 | .. compile-time calc
- total - total ms
- amount - number of launches
- last - last ms
- last 5 - average over the last 5 start ms
- last 10 - average over the last 10 ms runs
- avg - average generally ms
- dev deviation
Class Evaluation.java - Comparison of two methodsClass Timer.java - Measuring speed and statistics