Java programming logic (27) - Analysis packaging (in)

This section continues to investigate the packaging, introduces the Integer class, under section Character classes, Long and Integer similar, it is no longer a separate presentation, other basic classes have been introduced over, not repeat them.

What a simple Integer to introduce it? It has some binary operations, we look at, in addition, we also analyze its valueOf achieved.

Why should we care about code that implements it? In most cases, do not care, we will be able to use it, we mainly to learn, especially where the binary operation, is the basis of binary computer, but the code is often obscure, we want them to have a more to clear a deep understanding.

Let's look at bit flip.

Bit flip

usage

Integer has two static methods that can be flipped bit:

public static int reverse(int i)
public static int reverseBytes(int i)

Bit flip is an int as binary, bit for bit to the right of the left interchangeable, reverse is interchangeable bit, reverseBytes is interchangeable by byte. Let's look at an example:

Copy the code
int a = 0x12345678;
System.out.println(Integer.toBinaryString(a));

int r = Integer.reverse(a);
System.out.println(Integer.toBinaryString(r));

int rb = Integer.reverseBytes(a);
System.out.println(Integer.toHexString(rb));
Copy the code

 a is an integer, assigned hexadecimal, binary string which is output first, then the Reverse outputs a binary, hexadecimal reverseBytes final output, as output:

10010001101000101011001111000
11110011010100010110001001000
78563412

reverseBytes is inverted byte, a 78 byte hexadecimal representation, it is 12, so the result is 78563412 easier to understand.

Binary flip at first sight is wrong, because the output is not 32, 0:00 ignored previous output, we filled 32 Look:

00010010001101000101011001111000
00011110011010100010110001001000

The results on the right.

These two methods are how to achieve it?

reverseBytes

Look reverseBytes code:

Copy the code
public static int reverseBytes(int i) {
    return ((i >>> 24)           ) |
           ((i >>   8) &   0xFF00) |
           ((i <<   8) & 0xFF0000) |
           ((i << 24));
}
Copy the code

Parameter i is equal to 0x12345678, for example, we analyze the implementation process:

i >>> 24 unsigned right shift, the highest byte moved to the lowest bit, the result is 0x00000012.

(I >> 8) & 0xFF00, moved to the left of the second byte to the right of the second, i >> 8 result 0x00123456, then & 0xFF00, is reserved to the right of the second byte, the result is 0x00003400.

(I << 8) & 0xFF0000, moved to the right side of the second byte of the second left, i << 8 result 0x34567800, then & 0xFF0000, is reserved to the right of the third byte, the result is 0x00560000.

i << 24, the result is 0x78000000, the left most and right most bytes moved.

The four then results or operations |, the result is 0x78563412, so by left, right, and and or operations, to achieve the purpose of bytes reversed.

reverse

We look at reverse code:

Copy the code
public static int reverse(int i) {
    // HD, Figure 7-1
    i = (i & 0x55555555) << 1 | (i >>> 1) & 0x55555555;
    i = (i & 0x33333333) << 2 | (i >>> 2) & 0x33333333;
    i = (i & 0x0f0f0f0f) << 4 | (i >>> 4) & 0x0f0f0f0f;
    i = (i << 24) | ((i & 0xff00) << 8) |
        ((i >>> 8) & 0xff00) | (i >>> 24);
    return i;
}
Copy the code

Although this code is very short, but very obscure, in the end what does it mean?

The first line is a comment, "HD, Figure 7-1", What does it mean? HD is represented by a book called Hacker's Delight, HD its acronym, Figure 7-1 is a diagram for 7-1 book, the book, the content as shown below:

As can be seen, Integer in reverse code is a copy of the book the code in Figure 7-1, the interpreted code in the figure also shows, we translate it.

The basic idea of ​​the efficient implementation bit flip, single bit swap adjacent first, and then as a group of two, then the exchange of adjacent bits, followed by a group of four switching, then eight, sixteen, sixteen after the bit is complete. This idea applies not only to binary, decimal, is also applicable, for ease of understanding, we look decimal examples, such as digital flip 12345678,

The first round, the adjacent single digital interchanged, the result is:

21 43 65 87

Second round, a set of two numbers to the exchange of adjacent, the result is:

43 21 87 65

The third round, a group of four figures for the exchange of adjacent, the result is:

8765 4321

Flip completed.

For decimal, the efficiency is not high, but for binary, it is efficient because a plurality of adjacent binary bits can be exchanged in one instruction.

This line is adjacent to a single interchange:

x = (x & 0x55555555) <<  1 | (x & 0xAAAAAAAA) >>>  1;

5 is 0101,0x55555555 binary binary representation is:

01010101010101010101010101010101

x & 0x55555555 is to take the odd bit of x.

A binary is 1010,0xAAAAAAAA binary representation is:

10101010101010101010101010101010

x & 0xAAAAAAAA is taken even bit x.

(x & 0x55555555) <<  1 | (x & 0xAAAAAAAA) >>>  1;

X is represented by the odd bit to the left, even bits to the right, then | merger, achieve the purpose of adjacent bits interchangeable. This code can be optimized to have a small, only a constant 0x55555555, and then the second half of the first shift operation, becomes:

(i & 0x55555555) << 1 | (i >>> 1) & 0x55555555;

Similarly, the following code is two bits in a group of adjacent bits are interchangeable:

i = (i & 0x33333333) << 2 | (i & 0xCCCCCCCC)>>>2;

3 is 0011,0x33333333 binary binary representation is:

00110011001100110011001100110011 

x x & 0x33333333 is to take two of the lower half of a set.

C is 1100,0xCCCCCCCC binary binary representation is:

11001100110011001100110011001100

x x & 0xCCCCCCCC is to take part in two half-height on a set.

(i & 0x33333333) << 2 | (i & 0xCCCCCCCC)>>>2;

X is represented as a set to two, the lower half to the lower half of the displaced displacement high, high, then | combined, achieve the purpose of exchange. Similarly, the constant can be removed 0xCCCCCCCC, code can be optimized for:

(i & 0x33333333) << 2 | (i >>> 2) & 0x33333333;

Similarly, the following code is to the group of four bits, are exchanged.

i = (i & 0x0f0f0f0f) << 4 | (i >>> 4) & 0x0f0f0f0f;

The unit is switched in octets, that is, bytes reversed, can be written as follows a more direct form, and reverseBytes substantially identical codes.

i = (i << 24) | ((i & 0xff00) << 8) |
    ((i >>> 8) & 0xff00) | (i >>> 24);

Why write the code reverse so obscure it? Or write can not be easier to understand the way of it? For example, to achieve flip, a common idea is, first and last exchange, the second and penultimate swap until the middle of the two exchange is complete. If the data is not binary bits, the idea is good, but for the bits, the efficiency is relatively low.

CPU instructions and efficient operation can not be a single bit, the smallest unit of data that is typically 32-bit operation (32-bit machines), Further, the CPU can be efficiently implemented shift and logical operations, but more slowly Math.

reverse these characteristics is full CPU utilization, carried out in parallel and efficient exchange of adjacent bits, the same function can also be achieved in other ways easier to understand, but this is more efficient than the code difficult.

Cyclic shift

usage

Integer has two static methods can be cyclically shifted:

public static int rotateLeft(int i, int distance)
public static int rotateRight(int i, int distance) 

rotateLeft is Rotate Left, rotateRight is rotated right, distance is the number of bits moving, so-called cyclic shift, the shift is relative to the ordinary in terms of the general shift, such as left 2, the original top two there is no right will fill 0, and if it is shifted left two cycles, the original top two will move to the far right, like a ring around the same contact. Let's look at an example:

Copy the code
int a = 0x12345678;
int b = Integer.rotateLeft(a, 8);
System.out.println(Integer.toHexString(b));

int c = Integer.rotateRight(a, 8);
System.out.println(Integer.toHexString(c))
Copy the code

b is a 8-bit circular left shift result, c is a circular right shift of 8 bits result, the output is:

34567812
78123456

Implementation code

Code that implements these two functions are:

Copy the code
public static int rotateLeft(int i, int distance) {
    return (i << distance) | (i >>> -distance);
}
public static int rotateRight(int i, int distance) {
    return (i >>> distance) | (i << -distance);
}
Copy the code

These two functions are puzzling is negative, if the distance is 8, that i >>> - 8 What does it mean? In fact, the lowest actual number of direct digital shift is not back, but direct digital value of 5, or is a direct result of digital & 0x1f of. The reason for this is because the five largest represent 31, shifting more than 31 pairs int integer is invalid.

Understand the position of moving negative meaning, we are more likely to the above code, for example, -8 binary representation is:

11111111111111111111111111111000

Its lowest 5 is 11000, the decimal is 24, so i >>> - 8 is i >>> 24, i << 8 | i >>> 24 is rotated to the left eight.

Code above, i >>> - distance is i >>> (32-distance), i << - distance is i << (32-distance).

Bitwise find, count

There are other bits Integer operations, including:

public static int signum(int i)

Check the sign bit, positive returns 1, -1, 0 Negative return 0

public static int lowestOneBit(int i)

Find the right from the position number of the first one, which remain unchanged, the other bit is set to 0, the integer is returned. 3 For example, binary 11, binary result is 01, the decimal is 1, for 20, is 10100 binary, the result is 00100, is 4 decimal.

public static int highestOneBit(int i) 

Looking from the left of the first position number 1, which remain unchanged, the other bit is set to 0, the integer is returned.

public static int bitCount(int i)  

Find the binary representation of the number 1. 20 For example, a binary number is 2 10100,1.

public static int numberOfLeadingZeros(int i)

Beginning on the left is the number of consecutive zero. 20 For example, the binary is 10100, left 27 0.

public static int numberOfTrailingZeros(int i)

The right end is the number of consecutive 0's. 20 For example, the binary is 10100, on the right there are two zero.

About realization of the code, there are comments directed Hacker's Delight relevant chapters of this book, I will not repeat them.

The realization valueOf

When we mentioned in the previous section, create a wrapper class object, you can use the static valueOf method, you can also use the new direct, but it is recommended to use valueOf, why? We look valueOf code:

Copy the code
public static Integer valueOf(int i) {
    assert IntegerCache.high >= 127;
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}
Copy the code

It uses IntegerCache, which is inside a private static class code as follows:

Copy the code
private static class IntegerCache {
    static final int low = -128;
    static final int high;
    static final Integer cache[];

    static {
        // high value may be configured by property
        int h = 127;
        String integerCacheHighPropValue =
            sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
        if (integerCacheHighPropValue != null) {
            int i = parseInt(integerCacheHighPropValue);
            i = Math.max(i, 127);
            // Maximum array size is Integer.MAX_VALUE
            h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
        }
        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() {}
}
Copy the code

IntegerCache Integer representing cache, wherein the cache is a static array of Integer variables is initialized in the static initializer block, by default, a storage 127, a total of 256 corresponding to an integer from -128 to an Integer object.

In valueOf code, if the value is in the cache range of -128 to 127 which is the default, then the pre-acquired Integer object created directly from the IntegerCache, not only the range of the cache, the object is not created by new.

By sharing common objects, you can save memory space, since Integer is immutable, it is cached objects can safely be shared. Boolean / Byte / Short / Long / Character has a similar implementation. This sharing common object of thought, is a common design ideas, in <Design Mode> this works, it is given a name, called Flyweight, the English called Flyweight, ie the share of lightweight elements.

summary

This section describes some bit operating in Integer, operation code bit more obscure, but the performance is relatively high, we explain in detail some code which, if you want to know more about, according to comments, see this book Hacker's Delight. We also introduced the realization valueOf, introduces the Flyweight pattern.

The next section, let us explore Character

Guess you like

Origin www.cnblogs.com/ivy-xu/p/12584571.html