Thinking of a BUG: Java variables used in the final modification really can not modify its "value" do?

Foreword

In Java, when we want to tell the compiler that a variable whose value no longer needs to be changed after initialization, we used the final modification of the variable. And under what circumstances we have such a demand? For example, when we use the variables A thread defined in the thread B, we have to use the final modified the variable, the principle is prohibited CPU instruction in concurrency rearrangement, to prevent objects referenced by another thread in the object brought before the full completion of construction use. So in Java, final time to modify variables, we often people for the value of a variable can not be modified. So is it really? Below a case encountered in the development as an entry point to ponder analysis of the problem.

case

First look at the following piece of code is to use the camera preview screen is rendered when this pullback will go onPreviewFrame in each frame, bytes array which holds information about the frame of the screen, we can intercept face detection, screenshots, etc., are possible. However, in order to avoid repeated recycling garbage collector, defined here as the buffer pool synchronization byte array, each take a byte array from the buffer pool inside, the end of the pullback took it to return to the buffer pool inside, to ensure the re-use of all It is the same byte array and reduce memory consumption.

mCamera.startPreview();
mCamera.setPreviewCallbackWithBuffer(new Camera.PreviewCallback() {

    Pools.SynchronizedPool<byte[]> mByteArrayPool = new Pools.SynchronizedPool<byte[]>(1) {
        private final byte[][] mPool = new byte[1][mPreviewSize.getWidth() * mPreviewSize.getHeight() * 3 / 2];
        private int mPoolSize = mPool.length;

        @Override
        public byte[] acquire() {
            if (mPoolSize > 0) {
                final int lastPooledIndex = mPoolSize - 1;
                byte[] instance = mPool[lastPooledIndex];
                mPool[lastPooledIndex] = null;
                mPoolSize--;
                return instance;
            }
            return new byte[mPreviewSize.getWidth() * mPreviewSize.getHeight() * 3 / 2];
        }

        @Override
        public boolean release(@NonNull byte[] element) {
            if (mPoolSize < mPool.length) {
                mPool[mPoolSize] = element;
                mPoolSize++;
                return true;
            }
            return false;
        }
    };

    @Override
    public void onPreviewFrame(byte[] bytes, Camera camera) {
        final byte[] dst = mByteArrayPool.acquire();
        
        // 截屏(另外一个线程操作)
        sreenShot(dst);
        
        if (dst != null) {
            mByteArrayPool.release(dst);
        }

        camera.addCallbackBuffer(bytes);
    }
});
mCamera.addCallbackBuffer(new byte[mPreviewSize.getWidth() * mPreviewSize.getHeight() * 3 / 2]);
mCamera.addCallbackBuffer(new byte[mPreviewSize.getWidth() * mPreviewSize.getHeight() * 3 / 2]);
复制代码

Careful friends can see, dst here is defined as the final type, it stands to reason that its value should not be changed, however, give me feedback recently tested in the picture below this question, after thinking for the former Code after I confirmed the cause of this BUG occurred because of changes in final array of values ​​above causes the wrong shot content.

image

Can be seen in the above code, a screenshot using dst (byte array is converted into RGB) when the dst is also recovered into the buffer pool which, when not yet time screenshots completed, the next frame has been saved to the array dst inside array, leading screenshots when using both included on a screen, the screen also contains the next frame. This shows that even the dst array type is defined as final, but its "value" will still be changed.

So in the end why is this? Leafing through "Java programming ideas", which is so described:

For primitive types, final make constant value; and for object references, final make constant reference. Once the reference is initialized to point to an object, you can not then change it to point to another object. However, the object itself can indeed be modified, Java did not make any objects provide a constant way. This restriction also applies array, it is also the object.

to sum up

Whereby in Java, the type of the basic variables final modification, its value is constant; and for the objects (including arrays) using the final reference variable is modified, it refers to the object is constant, and value of the object can change.

This knowledge may not be a lot of people know, but after understanding for our daily development can avoid detours encountered extreme Bug, Bug Fix reduce a lot of time.

Guess you like

Origin juejin.im/post/5d831d7d6fb9a06ade1148b0