Before starting the main text of this article, let’s take a look at the following code:
The role of IntegerCache of the Integer class in Java
Package name: java.lang
File name: Integer.java
Method name: IntegerCache
The code of the method is as follows:
private static class IntegerCache { static final int high; static final Integer cache[]; static { final int low = -128; // high value may be configured by property int h = 127; if (integerCacheHighPropValue != null) { // Use Long.decode here to avoid invoking methods that // require Integer's autoboxing cache to be initialized int i = Long.decode(integerCacheHighPropValue).intValue(); i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - -low); } high = h; cache = new Integer[(high - low) + 1]; int j = low; for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); } private IntegerCache() {} }We see in the code that low is -128 and high is 127. In this way, in Java programming, if you want to use an object in the interval -128-127, you will directly use the object in this cache.
The above is a brief introduction to help everyone understand IntegerCache. The following is the main text of this article:
introduction
5 years ago, I posted a post on Hungarian about how to change IntegerCache in JDK. This approach is actually to go deep into Java runtime and is not actually used in scenarios. When you develop this research code, you can better understand how reflection works and how the Integer class implements it.
The Integer class has a private nested named IntegerCache, which contains Integer objects with values ranging from -127 to 128.
When the code needs to be enclosed from int type into an Integer object, and the value is within this range, the Java runtime will use this cache instead of creating a new Integer object. This is mainly for performance optimization considerations. We must keep in mind that many int values are often within this range in the program (such as the subscript index of an array).
The side effect of this is that, many times, when using the equal sign operator to compare two Integer objects, as long as the value is within range, it is valid. This is typical in unit testing. In run mode, when the value is greater than 128, the code execution will fail.
Using reflection to access IntegerCache classes can cause some strange side effects, note that this affects the entire JVM. If a servlet redefines a small Integer cache value, all other servlets running under the same Tomcat encounter the same problem.
There are other articles above in Lukas Eder and Sitepoint.
Now that I'm playing with the early releases of Java 9, all I've always had to do in my mind is to experiment with new Java versions. Before we start, let's take a look at how to do it in Java 8.
In Lukas's article, I posted his sample code here:
import java.lang.reflect.Field;import java.util.Random;public class Entropy { public static void main(String[] args) throws Exception { // Extract the IntegerCache through reflection Class << ? > clazz = Class.forName( "java.lang.Integer$IntegerCache"); Field field = clazz.getDeclaredField("cache"); field.setAccessible(true); Integer[] cache = (Integer[]) field.get(clazz); // Rewrite the Integer cache for (int i = 0; i < cache.length; i++) { cache[i] = new Integer( new Random().nextInt(cache.length)); } // Prove randomness for (int i = 0; i < 10; i++) { System.out.println((Integer) i); } }}This code accesses IntegerCache through reflection and then uses random values to fill the cache (naughty!).
We try to execute the same code in Java 9, don't expect any fun. When someone tries to violate it, it will find that Java 9 is more restrictive.
Exception in thread "main" java.lang.reflect.InaccessibleObjectException: Unable to make field static final java.lang.Integer[] java.lang.Integer$IntegerCache.cache accessible: module java.base does not "opens java.lang" to unnamed module @1bc6a36e
The program throws an exception, which will not occur in Java 8. It is equivalent to saying that objects are not model-based. Because of the java.base module, this is an integral part of the JDK. It is automatically imported when each Java program is started, and unnamed modules are not allowed to be opened. This exception is thrown when we try to set the field accessible property.
The objects we can easily access in Java 8 are now not accessible in Java 9 because the new module system protects this. The code can only access fields, methods and other information that can be accessed by reflection, only if the class is in the same module, or the module has a package opened for reflection access. This can be implemented through the module-info.java module definition file:
module myModule { exports com.javax0.module.demo; opens com.javax0.module.demo;} This module java.base is not necessary to open it on its own for reflection access, especially for unnamed modules. If we create a module and name it, the error message will contain the name of the module.
Can we open modules in the program? The java.lang.reflect.Module module has an addOpens method that can be done.
Is it feasible?
The bad news for developers is: It's not feasible. It can only open a package in a module in another module, and the package has been opened in that module by calling this method. This method can only allow modules to be passed to another module rights, provided that the other module has opened the same package in some way, and cannot open unopened packages (Translator's note: it's difficult to understand, isn't it?).
But at the same time, the good news is: Java 9 is not as easy to crack as Java 8. At least this vulnerability is closed. It seems that Java is beginning to develop towards a professional level, not just a toy (Translator's note: Who said Java is a toy?). In the near future, you can migrate projects in RPG and COBOL languages to Java very seriously. (Sorry, I was kidding)
Summarize
The above is the entire content of this article. I hope that the content of this article has certain reference value for everyone's study or work. If you have any questions, you can leave a message to communicate. Thank you for your support to Wulin.com.
This article is translated from: https://dzone.com/articles/hacking-the-integercache-in-java-9