Problem and a solution
Today, the company's JAVA project encountered a problem: when the xls file is generated, if there is a large amount of data, ArrayIndexOutOfBoundsException may occur.
Google found a BUG in the jxl package used in the item (open-source library used to handle xls files.
We also found a solution: Success. After a try, this method is indeed feasible.
Another solution-Reflection
However, I was reminded by my predecessors that I could give it a try --
Using java reflection, the constant to be modified is forcibly changed to the value we need at runtime.
-- In this way, you do not need to modify the jxl library. It is okay to add a few more words in our project, and the probability of a problem will be much lower.
So I studied it. Although I finally found that this method is not feasible in our project, it is still very rewarding.
First, use reflection to modify Private Static constants for the following Bean classes, where INT_VALUE is a Private Static constant
class Bean{ private static final Integer INT_VALUE = 100;}
Core code for modifying constants:
System. out. println (Bean. INT_VALUE); // obtain the INT_VALUE Field field Field = Bean of the Bean class. class. getField ("INT_VALUE"); // set the field access permission to true: remove the field affected by the private modifier. setAccessible (true);/* remove the effect of the final modifier and set the Field to modifiable */Field modifiersField = Field. class. getDeclaredField ("modifiers"); modifiersField. setAccessible (true); modifiersField. setInt (field, field. getModifiers ()&~ Modifier. FINAL); // set the field value to 200 field. set (null, 200); System. out. println (Bean. INT_VALUE );
The output result of the above Code is:
100
200
It indicates that Private Static constants are successfully reflected.
Restrictions
Note that the static constant type in the above Code is Integer -- but the field type to be modified in our project is not the packaging type Integer, but the basic type int of java.
After changing the constant type to int,
Class Bean {private static final int INT_VALUE = 100; // change the type from Integer to int}
When other code remains unchanged, the output result of the Code turns into a strange one:
100
100
In addition, during the debugging process, we found that during the second output, the Bean in the memory. INT_VALUE is already 200, but System. out. println (Bean. INT_VALUE) but the output result is still an odd 100 ?!
-- Is the reflection invalid?
I tried several other types and found that such seemingly invalid Types will occur on the basic types such as int, long, boolean, and String, if you change the type to the Integer, Long, or Boolean packaging type, or other types such as Date, Object will not be invalid.
Cause
After a series of research, speculation, search, and other processes, we finally found the cause:
For static constants of the basic type, JAVA replaces the reference in this constant in the Code with the corresponding constant value during compilation.
Reference: Modifying final fields in Java
That is, for the constant public static final int maxFormatRecordsIndex = 100, the code
if( index > maxFormatRecordsIndex ){ index = maxFormatRecordsIndex ;}
This code has been automatically optimized to the following by java during compilation:
if( index > 100){ index = 100;}
So when INT_VALUE is of the int type
System. out. println (Bean. INT_VALUE); // The compilation result is optimized as follows: System. out. println (100 );
Therefore, naturally, no matter how you modify Boolean. INT_VALUE, System. out. println (Bean. INT_VALUE), 100 is still stubbornly output.
-- This is a behavior of JVM optimization code to improve the running efficiency, but it will lead to the illusion that this constant value is not effective when we use reflection. This is probably a limitation of JAVA reflection-it is not too reliable to modify constants of the basic type. Appendix I DEMO code for testing
import java.lang.reflect.Field;import java.lang.reflect.Modifier;import java.util.Date;public class ForClass { static void setFinalStatic(Field field, Object newValue) throws Exception { field.setAccessible(true); Field modifiersField = Field.class.getDeclaredField("modifiers"); modifiersField.setAccessible(true); modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); field.set(null, newValue); } public static void main(String args[]) throws Exception { System.out.println(Bean.INT_VALUE); setFinalStatic(Bean.class.getField("INT_VALUE"), 200); System.out.println(Bean.INT_VALUE); System.out.println("------------------"); System.out.println(Bean.STRING_VALUE); setFinalStatic(Bean.class.getField("STRING_VALUE"), "String_2"); System.out.println(Bean.STRING_VALUE); System.out.println("------------------"); System.out.println(Bean.BOOLEAN_VALUE); setFinalStatic(Bean.class.getField("BOOLEAN_VALUE"), true); System.out.println(Bean.BOOLEAN_VALUE); System.out.println("------------------"); System.out.println(Bean.OBJECT_VALUE); setFinalStatic(Bean.class.getField("OBJECT_VALUE"), new Date()); System.out.println(Bean.OBJECT_VALUE); }}class Bean { public static final int INT_VALUE = 100; public static final Boolean BOOLEAN_VALUE = false; public static final String STRING_VALUE = "String_1"; public static final Object OBJECT_VALUE = "234";}
Code output
100100------------------String_1String_1------------------falsetrue------------------234Fri Apr 25 00:55:05 CST 2014
Description
-- The Boolean and Object type constants are modified correctly, while the changes to the basic types of int and String are "invalid ".
Synchronous publishing in http://www.barryzhang.com/archives/188
Advertise my new blog. Welcome to visit Kazakhstan ~ :BarryZhang.com