Summary: This article describes how to apply code dynamic generation technology in a normal Java program, and test, compare performance of various implementation methods. Outline: First, Overview / II, Expression Calculator / III, Interpretation of Four, Resolution / V. Compilation / Sixth Java programs cannot be compared with C or C programs. To this end, Java has been performing unremitting efforts in performance optimization, especially the performance optimization mechanism, and saving many blame. However, no matter what the performance has increased in Java, people have no end to the code performance. Obviously, Java's performance does not function in some operations, which is determined by the characteristics of the Java language, for example, in order to cross the platform, for example, for cross-platform. On the other hand, since Java has many unique features, it can take advantage of many other languages, dynamic code student achievement is one of them. The so-called dynamic code generation is a process of dynamically generating a code during runtime. The dynamically generated code and the generated program run in the same JVM, and the access method is similar. Of course, similar to other optimization techniques, dynamic code generation is only applicable to certain types of tasks. JSP may be an example of people's most familiar dynamic code generation. The Servlet engine can send the client's request to the servlet, but servlet is born is a static structure. Before starting the server, servlet must generally compile and configure it. Although servlet has many advantages, servlet is slightly in terms of flexibility. JSP technology breaks through the SERVLET restriction, allowing the servlet based on JSP files based on the runtime. When the client issues a request for the JSP file, the servlet engine issues a request to the JSP engine, the JSP engine processes the JSP file and returns the result. The JSP file is a text description of a series of actions. The execution result of this series of action is to return to the user. Obviously, if each user's request arrives, the JSP page is performed by explaining, and the overhead is definitely more big. Therefore, the JSP engine compiles the JSP page dynamically creates a servlet. Once the JSP page is changed, the JSP engine will dynamically create a new servlet. Here, the advantages of dynamic code generation techniques are very obvious - both satisfying the flexibility requirements and does not affect performance. When compiling servlets or even start the server, the system's behavior is not fully fixed; at the same time, the response time is reduced because it is not necessary to explain the execution JSP files when the request is to answer each request. Second, the expression calculator Let's take a look at how to use dynamic code generation technology in a normal Java program. The examples of this paper are a simple four arithmetic expression calculator that calculates a suffix expression such as "4 $ 0 $ 1 *", where $ 0 and $ 1 represent variable 0, variable 1, respectively. There may be three symbols in the expression: variables, constants, operators. The suffix expression is a stack-based computational expression, and the processing process is performed in order from left to right. It is still in front of the expression: first press 4 and variable 0 into the stack, the next character is operator " " Therefore, two values (4 and variable 0) of the top of the stack (4 and variable 0) are then replaced with two values of the top of the stack. Next, press 1 to press the stack, since the next is the operator "*", the multiplication operation is performed on the two values of the stack top. If this expression is converted into a usual algebraic expression (i.e., it is "(4 $ 0) * $ 1".
If the two variables are "[3, 6]", the calculation result of the expression is (4 3) * 6 = 42. In order to compare the performance differences of code dynamic generation and routine programming, we will implement an expression calculator in a variety of different ways and then test the performance of each calculator. All expression calculars in this article implement (or implicitly implemented) Calculator interface. The Calculator interface has only an evaction method. Its input parameter is an integer array, and the return value is an integer representing the calculation result. //Calculator.java
Public interface Calculator {
Int evAlate (int "arguments);
}
Third, the interpretation method first let's take a simple but efficient expression calculator, which uses the Stack object to calculate expression. Each calculation, the expression is re-analyzed, so that the explanation can be referred to. However, the symbol analysis of the expression is only executed when the object is created, avoiding the StringTokenizer class to bring too much overhead.
//Simplecalculator.java
Import java.util.arraylist;
Import java.util.stack;
Import java.util.StringTokenizer;
Public class simplecalculator imports colculator {
String [] _TOKS; // Symbol list
Public SimpleCalculator (String Expression) {
// Construct the symbol list
ArrayList List = New ArrayList ();
StringTokenizer tokenizer
= New StringTokenizer (Expression);
While (tokenizer.hasmoreToKens ()) {
List.add (tokenizer.nextToken ());
}
_TOKS = (String [])
List.toArray (New String ");
}
// Replace the variable value into the expression in the expression,
/ / Then return to the calculation result of the expression
Public int evALUATE (int [] args) {
Stack stack = new stack ();
For (int i = 0; i <_toxs.length; i ) {
String tok = _TOKS [i];
// Take the variable at the beginning of '$'
IF (Tok.StartSwith ("$")) {
INT varnum = integer.parseint (tok.substring (1));
Stack.push (new integer (args [varnum));
} else {
Char opchar = tok.charat (0);
INTOP = " - * /". Indexof (opchar);
IF (OP == -1) {
// constant
Stack.push (Integer.Valueof (Tok));
} else {
// operator
INT Arg2 = (Integer) stack.pop ()). INTVALUE ();
INT Arg1 = (Integer) stack.pop ()). INTVALUE ();
Switch (OP) {
/ / Perform the specified operation on the two values of the stack
Case 0:
Stack.push (new integer (arg1 arg2));
Break;
Case 1:
Stack.push (New Integer (Arg1 - Arg2)); BREAK;
Case 2:
Stack.push (new integer (arg1 * arg2));
Break;
Case 3:
Stack.push (new integer (arg1 / arg2));
Break;
DEFAULT:
Throw new runtimeException
("The operator is not legal:" tok);
}
}
}
}
Return ((Integer) stack.pop ()). INTVALUE ();
}
}
As can be seen from the performance test data later in this article, this expression calculation method is quite low. For occasions that occasionally need to calculate expressions, it may apply, but we have better way of processing. 4. If the resolution method is often calculated, a better way is to analyze the expression, apply the Composite design mode, and construct an expression tree. We call this expression calculation method as the resolution method. As shown in the following code, the internal structure of the tree represents the computational logic of the expression, and thus avoids the calculation logic at a time computational expression.
//CalculatorParser.java
Import java.util.stack;
Import java.util.StringTokenizer;
Public class calculatorParser {
Public Calculator Parse (String Expression) {
// Analytical expression, construct of each symbol of the expression
// tree structure.
Stack stack = new stack ();
StringTokenizer Toks
= New StringTokenizer (Expression);
While (toks.hasmoretoKens ()) {
String tok = toks.nextToken ();
IF (Tok.StartSwith ("$")) {
// Take the variable at the beginning of '$'
Int Varnum
= Integer.Parseint (tok.substring (1));
Stack.push (New VariableValue (Varnum));
} else {
INTOP = " - * /". Indexof (Tok.Charat (0));
IF (OP == -1) {
//constant
INT VAL = Integer.Parseint (TOK);
Stack.push (New ConstantValue (VAL));
} else {
// operator
Calculator node2 = (calculator) stack.pop ();
Calculator node1 = (calculator) stack.pop ();
STACK.PUSH (
New Operation (Tok.Charat (0), Node1, Node2);
}
}
}
Return (Calculator) stack.pop ();
}
// constant
Static Class ConstantValue IMPLEments Calculator {
Private int _Value;
ConstantValue {{INT VALUE
_Value = value;
Public int evALUATE (int [] args) {
Return_Value;
}
// variable
Static Class VariableValue IMPLEments Calculator {
Private int _varnum;
VariableValue (int varnum) {
_varnum = varnum;} public int evALUATE (INT [] args) {
Return args [_varnum];
}
// operator
Static Class Operation Implements Calculator {
Char_op;
Calculator_arg1;
Calculator_arg2;
Operation (Char OP, Calculator Arg1, Calculator Arg2) {
_op = OP;
_arg1 = arg1;
_arg2 = arg2;
}
Public int evAlate (int Args []) {
INT VAL1 = _Arg1.evaluate (ARGS);
INT VAL2 = _Arg2.evaluate (ARGS);
IF (_op == ' ') {
RETURN VAL1 VAL2;
} else if (_op == '-') {
RETURN VAL1 - VAL2;
} else if (_op == '*') {
RETURN VAL1 * VAL2;
} else if (_op == '/') {
Return Val1 / VAL2;
} else {
Throw new runtimeException ("The operator is not legal:" _o);
}
}
}
}
Since the computational logic of the expression has parsed in advance, the performance of the CalculatorParser is significantly higher than the first calculator executed by interpretation. Despite this, we can further optimize the code through code dynamic generation techniques.