BUGを考えて:最後の修正に使用されるJava変数は、本当にその「値」を変更することはできませんか?

序文

我々は値変数は、もはや初期化後に変更する必要があるコンパイラを伝えたい時にJavaでは、我々は変数の最終修正を使用しました。そして、どのような状況の下で、我々はこのような要望を持っていますか?我々は、スレッドがスレッドBで定義された変数を使用する場合、例えば、我々は最終的な変数を修飾使用する必要があり、原理的には、オブジェクトに別のスレッドによって参照されるオブジェクトを防止するために、同時実行転位にCPU命令を禁止されています建設用のフル完了する前にもたらしました。Javaで、最後の時間は、変数を変更するので、私たちはしばしば、変数の値の人々を変更することはできません。だから、本当にありますか?エントリーポイントとして開発で遭遇ケースの下には、問題の分析を熟考します。

場合

以下のコードを初めて目には、このプルバックは、各フレームでonPreviewFrameを行くときにレンダリングされたカメラのプレビュー画面を使用することで、私たちは顔検出を傍受することができ、画面のフレームに関する情報を保持する配列をバイト、スクリーンショットなど、可能です。バッファプールの同期バイト配列として、それぞれが内部のバッファプールからのバイト配列を取るしかし、繰り返しリサイクルガベージコレクタを避けるために、ここで定義され、プルバックの終わりには、すべての再利用を確保するために、内部のバッファプールに戻るには、それを取りましたそれは同じバイト配列であり、メモリの消費量を削減します。

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]);
复制代码

慎重な友人がDSTここで、最終的な型として定義され、見ることができ、それはその値を変更してはならないことを理にかなって、しかし、元のコードのために考えた後、私は最近、この問題以下の絵でテストし、フィードバックを与えます私が確認した後、このバグの原因は、理由値の最終配列の変化により上記の間違ったショットのコンテンツを引き起こし発生しました。

画像

DSTもまだ時間スクリーンショットが完了したとき、次のフレームが内部配列dstに保存されている、バッファプールに回収された場合(バイト配列をRGBに変換される)上記のコード、DSTを使用してスクリーンショットで見ることができますアレイは、画面上に含ま両方を使用する際のスクリーンショットをリードし、画面には、次のフレームを含みます。これはさえDST配列タイプは、最終のように定義されていることを示しているが、その「値」がまだ変更されます。

だから、最後に、なぜこれは何ですか?そのように記載された「Javaプログラミングのアイデア」、めくります:

プリミティブ型、最終的なメーク一定値のため、およびオブジェクト参照のために、最終的な一定の基準を作ります。参照がオブジェクトを指すように初期化されたら、その後、別のオブジェクトを指すように変更することはできません。しかし、オブジェクト自体が実際に変更することができ、Javaは任意のオブジェクトが一定の方法を提供しませんでした。この制限は、それはまた、オブジェクトである、配列を適用します。

概要

これによりJavaでは、基本変数の最終変形のタイプは、その値は一定であり、オブジェクトが一定であるように変更され、最終的な参照変数を使用して、(アレイを含む)目的のために、それが意味する、とオブジェクトの値を変更することができます。

この知識は、多くの人が知っているが、私たちの日常の開発のために理解した迂回路はバグが多くの時間を減らす修正、極端なバグに遭遇を避けることができないかもしれません。

おすすめ

転載: juejin.im/post/5d831d7d6fb9a06ade1148b0