Tag: Choose New to confuse code Gen Pass during to generate security
Read Catalogue
- Recommendation 26: Beware of NULL values for wrapper types
- Recommendation 27: Size comparison of discreet packaging types
- Recommendation 28: Prioritize using an integer pool
- Recommendation 29: Priority selection of basic types
- Recommendation 30: Don't randomly set random seeds
Back to top tip 26: Beware of NULL values for wrapper types
We know that Java introduces wrapper types (Wrapper Types) to solve basic types of instantiation problems, so that a basic type can also participate in the object-oriented programming world. In Java5, generics are "no" to the basic type, and if you put an integral type in the list, you must use the integer wrapper type. Let's look at a piece of code:
1 Import java.util.ArrayList; 2 Import java.util.List; 3 4 public class Client26 {5 6 public static int TestMethod (list<integer> List) {7 int count = 0; 8 for (int i:list) {9 count + = i;10 }11 return count;12}13 public static void Main (string[] args) { list<integer> List = new arraylist<integer> (); list.add (1); List.add (2); 18 list.add (null); System.out.println (TestMethod (list)); }21}
TestMethod receives an integer list parameter, calculates the sum of all elements, which is common in statistics and projects, and then writes a test testmethod that puts 1, 2, and Null values in the list in the main method, and then calls the method calculation, Now think about whether or not to error. No, the basic type and packing type can be freely converted by auto-boxing (autoboxing) and auto-unpacking (autounboxing), and Null should be converted to 0, is that true? After running the result is: Exception in thread "main" java.lang.NullPointerException run failure, report null pointer exception, we think about it a little bit quickly know why: in the program for Loop, the implication of a unboxing process In this procedure, the wrapper type is converted to the base type. We know that unpacking is done by calling the Intvalue method of the wrapper object, because the wrapper type is null, and it is unavoidable to access its Intvalue method to report a null pointer exception. The problem is clear, the modification is simple, add a null value check, the code is as follows:
public static int TestMethod (list<integer> List) { int count = 0; for (Integer i:list) { count + = (i! = null)? i:0; } return count; }
An example of integer and int illustrates the problem of unpacking, and the same problem exists with the unpacking process of the other 7 wrapper objects. The wrapper object and the unboxing object can be freely converted, which is not false, but to remove the null value, the null value cannot be converted to the base type. For this issue, let's remember that a null value check is done when the wrapper type participates in the operation.
Back to top recommendation 27: The size comparison of discreet packaging types
The basic type is can compare size, its corresponding wrapper type all implements the comparable interface, also explains this problem, let us compare two packing type size, the code is as follows:
1 public class Client27 {2 public static void Main (string[] args) {3 integer i = new integer; 4 integer j = new Integer (100); 5 Compare (I, j); 6 } 7 8 public static void compare (integer i, Integer j) {9 System.out.println (i = = j); System.out.println (i > J); System.out.println (i < j); }14}
The code is simple, produces two integer objects, and then compares two size relationships, since the wrapper type and the basic type is free to convert, then the above code can be printed out two equal values? Let the facts speak, and the result is as follows:
False false
Unexpectedly is 3 false, that is to say two values are not equal, also no size relationship, this is too strange. No surprise, we come to one by one explanations:
- I==j: in Java, "= =" is used to determine whether the two operands have an equal relationship, if the basic type is to determine whether the value is equal, if the object is to determine whether it is an object two references, that is, the address is equal, here is obviously two objects, two addresses cannot be equal.
- I>j and I<j: In Java, ">" and "<" are used to determine the size relationship of two numeric types, note that only the judgement of the number type, for the integer wrapper type, is based on the return value of its intvalue () method (that is, its corresponding base type) The comparison (the other packing types are compared according to the corresponding value value, such as Doublevalue,floatvalue, etc.), it is clear that the two will not be able to have a size relationship.
The problem is clear, the modification is always easier, directly using the integer instance CompareTo method can be, but this kind of problem arises more should be the habit problem, as long as the comparison between two objects should adopt the corresponding method, rather than through the Java default mechanism to deal with, Unless you're sure you know this very well.
Back to top recommendation 28: Prioritize using an integer pool
In the previous recommendation, we explained the comparison of the packaging objects, this recommendation will continue to discuss the relevant issues in depth, first look at the following code:
1 Import Java.util.Scanner; 2 3 public class Client28 {4 public static void Main (string[] args) {5 Scanner input = new Scanner (system.in ); 6 while (Input.hasnextint ()) {7 int tempint = Input.nextint (); 8 System.out.println ("\n=====" + Tempint + " Equal judgment ===== "); 9 //Two objects created by new, integer i = new Integer (tempint), integer j = new Integer (tempint) System.out.println ("New Generated object:" + (i = = j)); The base type is converted to the wrapper type after the comparison between i = tempint;15 j = tempint;16 Sys Tem.out.println ("Primitive type Conversion object:" + (i = = j)); //Generate an instance by static method, i = integer.valueof (tempint); Integer.valueof (tempint); System.out.println ("ValueOf objects produced:" + (i = = j)); }22 }23}
Enter multiple numbers, and then produce an integer object in 3 different ways to determine whether it is equal, and note that "= =" is used here, which means that the same object is not judged. We enter three numbers 127, 128, 555, and the results are as follows:
127
The equal judgment of =====127 =====
New object created by: false
Object of the base type conversion: TRUE
ValueOf Generated object: True
128
The equal judgment of =====128 =====
New object created by: false
Object of the base type conversion: false
ValueOf generated object: false
555
The equal judgment of =====555 =====
New object created by: false
Object of the base type conversion: false
ValueOf generated object: false
It is incredible that the comparison of the number 127 and the other two different numbers, its boxing action produced by the object is the same object, valueof produced is the same object, but the number greater than 127 and 128 and 555 is not the same object produced in the comparison process, which is why? Let's take an explanation.
(1), the integer object created by new
New declares that it is to generate an object, no gave, this is two objects, the address must be unequal, the comparison result is false.
(2), boxing-generated objects
For this, the first thing to say is that the boxing action is implemented by the ValueOf method, that is, the latter two algorithms are the same, the result is certainly the same, and now the question is: How is valueof generated object? Let's read the following integer.valueof source code:
1/** 2 * Returns an {@code Integer} instance representing the specified 3 * {@code int} value. If a new {@code Integer} instance is not 4 * required, this method should generally being used in preference to 5 * The constructor {@link #Integer (int)}, as this method was likely 6 * to yield significantly better space and time per Formance by 7 * Caching frequently requested values. 8 * 9 * This method would always have the cache values in the range-128 to 127,10 * inclusive, and could cache other V Alues outside of this range.11 *12 * @param i a {@code int} value.13 * @return an {@code Integer} instanc E representing {@code i}.14 * @since 1.515 */16 public static Integer valueOf (int i) {+ assert int Egercache.high >= 127;18 if (i >= integercache.low && i <= integercache.high) retur N Integercache.cache[i + (-integercache.low)];20 return new Integer (i); +}
The meaning of this code is already very clear, if it is 128 to 127 between the int type converted to an integer object, then directly from the cache array, what is in the cache array, JDK7 source code is as follows:
1/** 2 * Cache to support the object identity semantics of autoboxing for values between 3 * -128 and 127 (in clusive) as required by JLS. 4 * 5 * The cache is initialized on first usage. The size of the cache 6 * May is controlled by the-xx:autoboxcachemax=<size> option. 7 * During VM initialization, Java.lang.Integer.IntegerCache.high property 8 * is set and saved in the Priva Te System Properties in the 9 * Sun.misc.VM class.10 */11 private static class Integercache {s tatic final int low = -128;14 static final int high;15 static final Integer cache[];16 + static { //High value is configured by property19 int h = 127;20 String integercachehig Hpropvalue =21 sun.misc.VM.getSavedProperty ("Java.lang.Integer.IntegerCache.high"), if (inte Gercachehighpropvalue! = NULL) {$ int i = parseint (IntegercachehiGhpropvalue); i = Math.max (i, 127); +//Maximum array size is Integer.max_value26 h = math.min (i, Integer.max_value-(-low));}28 high = h;29-cache = n EW integer[(high-low) + 1];31 Int j = low;32 for (int k = 0; k < cache.length; k++) 33 CACHE[K] = new Integer (j + +),}35-Integercache () {}37}
The cache is a static array of Integercache inner classes that holds an integer object between 128 and 127. When the wrapper object is generated by valueof, if the int parameter is from 128 to 127, the object is obtained directly from the integer pool, and the int type that is not in that range generates the wrapper object through new.
Understand this, to understand the above output will be solved, 127 of the packaging object is directly from the whole pool, no matter how many times you enter the number 127, the object is the same, the address is naturally equal. and 128, 555 out of the range of the whole pool, is to create a new object through new, the address is different, of course, is not equal.
The above understanding is also the principle of the whole pool, the existence of an integral pool not only improves system performance, but also saves memory space, which is why we use an integral pool, that is, when declaring wrapper objects using valueof generation, rather than through the constructor to generate the reason. By the way, it is best to use the Equals method when judging whether objects are equal, and avoid using "= =" to produce unintended effects.
Note: Wrapper instances generated by valueof of the wrapper type can significantly improve spatial and temporal performance.
Back to top recommendation 29: Priority selection of basic types
The wrapper type is a class that provides very useful functions such as construction methods, type conversions, comparisons, and then, after Java5, the conversion to the basic type, which makes the packaging type more powerful, and is widely used in the development of packaging types have been everywhere, but regardless of security, performance, Or from a stability standpoint, the basic type is the preferred scenario. Let's look at a piece of code:
1 public class Client29 {2 public static void Main (string[] args) {3 Client29 c = new Client29 (); 4 int i = 140; 5 //pass int type and Integer type 6 c.testmethod (i), 7 C.testmethod (new Integer (i)), 8 } 9 public void TestMethod (Long a) {one System.out.println ("Method of basic type is called"); }13 public void TestMethod (Long a) {15 System.out.println ("method of wrapper type is called"); 17}
In the above program first declared an int variable i, and then widened into a long type, and then call the TestMethod () method, respectively, pass the basic type of int and long and the packing type, you think the program can compile? If you can compile, what is the output?
First of all, this program is absolutely capable of compiling. However, say can not compile the classmate still have a brain, you may guess the following these places cannot compile:
(1), TestMethod method overload problem. The two TestMethod () methods that are defined implement overloading, a formal parameter is a basic type, and a formal parameter is a wrapper type, which is normal. Although the basic types and wrapper types have automatic boxing, automatic unpacking, and do not affect their overloads, automatic unpacking (boxing) occurs only when the assignment is assigned, and does not relate to the compilation overload.
(2), C.testmethod (i) error. I is an int type, passed to TestMethod (long a) is not a problem, the compiler will automatically widen the type I and convert it to long, which is the basic type of conversion law, there is no problem.
(3), C.testmethod (new Integer (i)) error. The code does not have the TestMethod (integer i) method, it is not possible to receive an integer type of parameters, and the integer and long two wrapper type is a sibling, not an inheritance relationship, that is to say that the compilation failed? No, compile-time success, and later explain why the compilation succeeded here.
Now that the compilation has passed, let's look at the output:
the method of the base type is called
The method of the base type is called
The output of C.testmethod (i) is normal, as we have explained, and the second output is confusing, why call the TestMethod (long a) method? This is because automatic boxing has one important principle: the basic type can be widened first, then converted into a wide type of wrapper type, but not directly into a wide type of wrapper type. This sentence is more awkward, simply said, int can be widened into a long, and then turn into a long object, but not directly into the package type, note that this refers to the automatic conversion, not by the constructor, in order to explain this principle, we look at an example:
1 public class Client29 {2 public static void Main (string[] args) {3 Client29 c = new Client29 (); 4 int i = 140; 5 C.testmethod (i); 6 } 7 8 public void TestMethod (Long a) {9 System.out.println ("method of wrapper type is called"); Ten }11}
The compilation of this program is not passed, because I is an int type and cannot be automatically converted to long, but the following code can be modified to pass:
int i = 140; Long a = (long) i; C.testmethod (a);
That is, int widens the transformation into long and then automatically converts to long, and the rules show that we continue to see how TestMethod (Integer.valueof (i)) is called, integer.valueof (i) The return is an integer object, which is true, but integer and int can be converted to each other. No TestMethod (Integer i) method? It doesn't matter, the compiler tries to convert an argument call of type int, Ok, this time, it is the same as TestMethod (i), and the result of widening into long---is obvious. The entire TestMethod (integer.valueof (i)) is executed as follows:
(1), I wrapped into an integer object by the ValueOf method
(2), because there is no TestMethod (integer i) method, the compiler will be "smart" to convert the Integer object to int.
(3), int auto Widening to long, compile end
There is a convenient way to use the wrapper type, but it also causes some unnecessary confusion, such as our example, if the two overloaded methods of TestMethod () use the basic type, and the argument is the basic type, it will not produce the above problem, and the program is more readable. Automatic packing (unpacking) is very convenient, but the problem is also very serious, we do not even know which method to execute.
Note: Reiterate that the basic type is preferred.
Back to top tip 30: Don't randomly set random seeds
Random numbers use more places, such as encryption, obfuscation, and we use random numbers to expect a unique, non-counterfeit number to avoid confusing the same business data. In Java projects, where random numbers are usually obtained through the Math.random method and the random class, let's look at a piece of code:
1 Import java.util.Random; 2 3 public class Client30 {4 public static void Main (string[] args) {5 random r = new Random (), 6 for (in T I=1; i<=4; i++) {7 System.out.println ("+i+" Times: "+r.nextint ()"); 8 9 }10 }11}
The code is very simple, we generally get random numbers, run this program, we can see that three printing, random numbers are not the same, even if the results are different, this is the reason we want to random numbers, we look at the following program:
1 public class Client30 {2 public static void Main (string[] args) {3 random r = new random (+); 4 for (int I=1; i<=4; i++) {5 System.out.println ("+i+" Times: "+r.nextint ()); 6 7 }8 }9}
The above uses the random parameter structure, the operation result is as follows:
1th Time: 1244746321
2nd time: 1060493871
3rd time: 1826063944
4th Time: 1976922248
Different computer output random number is also different, but one thing is the same: on the same machine, do not run how many times, the print random number is the same, that is, the first run, will print out these random numbers, the second run or print out the three random numbers, as long as the same machine, will always print the same random number, it seems random number is not random, what is the problem?
That is because the seed of the generated random number is fixed, in Java, the generation of random numbers depends on the seed, the relationship between the random number and the seed obeys the following two principles:
- Different seeds, producing different random numbers
- Same seed, even if different instances produce the same random number
After reading the above two rules, we'll look at this example, and we'll see that the problem is on the structure of the argument, the default seed of the Random class (no parameter construct) is the return value of System.nonotime () ( JDK1.5 version before the default seed is the return value of System.currenttimemillis (), note that this value is the number of nanoseconds from a fixed point in time, different operating systems and hardware have different fixed point of time, that is different operating system its nanosecond value is different, And the same operating system nanosecond value will be different, the random number is naturally different. (By the way, System.nonotime cannot be used to calculate dates, because the "fixed" time is indeterminate, the nanosecond value may even be negative, which is different from System.currenttiemmillis).
The new random (1000) display sets the random seed to 1000, runs multiple times, and, although the instances are different, gets the same four random numbers, so do not set a random seed unless necessary.
By the way, there are two ways to get different random numbers in Java: through, The Java.util.Random class obtains the random number principle and the Math.random method is same, the Math.random method also by generates an instance of the random class, then delegates the Nextdouble () method, the two sides, does not have the difference.
Note: Do not set a random number seed, unless necessary.
Reprint---Write high-quality code: 151 recommendations for improving Java programs (2nd: Basic type ___ recommended 26~30)