【転】JAVA面接問題解惑シリーズ(十一)——これらの演算子を覚えていますか?


いくつかの演算子はJAVA言語の中で存在していますが、実際の開発ではあまり使われていないかもしれませんが、面接問題ではよくその姿が現れます.これらの演算子の意味と使い方を覚えていますか.
自己加算(+)演算子と自己減算(-)演算子
まずいくつかの質問に答えましょう.
Javaコード
int i = 0; 
int j = i++; 
int k = --i;

このコードが実行された後、iはいくらですか?jはいくらですか.kはいくらですか.簡単すぎますか?はい、続けます.
Javaコード
int i = 0; 
int j = i++ + ++i; 
int k = --i + i--;

コード実行後i,j,kはそれぞれいくらに等しいですか?それとも簡単ですか?はい、続けます.
Javaコード
int i=0; 
System.out.println(i++);

このコードの実行後の出力結果は何ですか?0?1?
Javaコード
float f=0.1F; 
f++; 
double d=0.1D; 
d++; 
char c='a'; 
c++;

上のコードはコンパイルできますか?どうして?ここまで順調に答えられると、自己増加演算子と自己減少演算子の把握がうまくいっていることを示します.
上記のいくつかの問題を分析するために、まず関連知識を振り返ってみましょう.
1、自己増加(++):変数の値に1、接頭辞式(例えば++i)、接尾辞式(例えばi++)を加える.接頭辞式はまず1を加えてから使用します.接尾辞は先に使ってから1を加える.
2、自己減算(-):変数の値を1、接頭辞式(例えば--i)、接尾辞式(例えばi-).接頭辞式はまず1を減らしてから使用します.接尾辞は先に使ってから1を減らす.
第1の例では、int j=i++である.接尾辞式であるため、iの値はまずjが与えられ、その後1が増加するので、この行のコードが実行されると、i=1、j=0となる.一方int k=--i;接頭辞式であるため、iはまず1を減算してからその値をkに与えるので、この行のコードが実行されると、i=0、k=0となる.
第2の例では、int j=i++++iについて、まずi++を実行し、iの値0を加算(+)に用い、その後iが付加価値から1になり、その後++iを実行し、iが先に2に増加し、その後加算演算に用いられ、最後にiの2回の値を加算した結果1+2=3がjに与えられるため、この行のコードの実行が完了するとi=2、j=3となる.int k=--i+i-;同様の考え方で分析すると,具体的な過程はここでは後述しないが,結果はi=0,k=2であるべきである.
自己加算演算子と自己減算演算子は、次の規則に従います.
1、整数タイプbyte、short、int、long、浮動小数点タイプfloat、double、文字列タイプcharに使用できます.
2、Java 5.0以上のバージョンでは、基本タイプに対応するパッケージクラスByte、Short、Integer、Long、Float、Double、Characterに使用できます.
3、それらの演算結果のタイプは、演算された変数のタイプと同じである.
次の例では、コンパイルして実行できる上記の法則を検証します.
Javaコード
public class Test { 
    public static void main(String[] args) { 
        //    
        byte b = 0; 
        b++; 
        //    
        long l = 0; 
        l++; 
        //     
        double d = 0.0; 
        d++; 
        //     
        char c = 'a'; 
        c++; 
        //          
        Integer i = new Integer(0); 
        i++; 
    } 
} 

ビット単位演算子
ビット演算子は全部で何種類あるか言えますか?次のリストを比較して、あなたの記憶から消えたものがありますか?
1、ビットと演算(&):二元演算子.演算された2つの値がいずれも1の場合、演算結果は1である.それ以外の場合は0です.
2、ビット単位または演算(|):二元演算子.演算された2つの値がいずれも0の場合、演算結果は0である.それ以外の場合は1です.
3、ビット別または演算(^):二元演算子.演算された2つの値のいずれかが1であり、もう1つが0である場合、演算結果は1である.それ以外の場合は0です.
4、ビット別非演算(~):一元演算子.演算された値が1の場合、演算結果は0である.演算された値が0の場合、演算結果は1となる.
ここでは、論理演算子(演算&&、または演算|、非演算!)とは異なります.操作は、ブール値trueまたはfalse、またはブール値を生成できる式です.ビット単位演算子は、ビットがバイナリビットであるため、バイナリの0と1を操作します.ビット演算子の実行原理を説明するついでに、論理演算子との違いについて説明します.
1、論理演算子はブール値またはブール値を生成できる式しか操作できない.ビット演算子はbyte、short、int、longを含む整数値を操作できますが、float値(floatおよびdouble)は操作できません.文字型(char)値も操作できます.ビット演算子はオブジェクトを操作できませんが、Java 5.0以上のバージョンでは、byte、short、int、long、charに対応するパッケージクラスは例外です.JAVA仮想機会が自動的に対応する基本タイプのデータに変換するためです.
次の例では、この法則を検証します.
Javaコード
public class BitOperatorTest { 
    public static void main(String[] args) { 
        //    
        byte b1 = 10, b2 = 20; 
        System.out.println("(byte)10 & (byte)20 = " + (b1 & b2)); 
        //      
        char c1 = 'a', c2 = 'A'; 
        System.out.println("(char)a | (char)A = " + (c1 | c2)); 
        //           
        Long l1 = new Long(555), l2 = new Long(666); 
        System.out.println("(Long)555 ^ (Long)666 = " + (l1 ^ l2)); 
        //     
        float f1 = 0.8F, f2 = 0.5F; 
        //     ,               
        // System.out.println("(float)0.8 & (float)0.5 = " + (f1 & f2)); 
    } 
}

実行結果:
*(byte)10 & (byte)20 = 0
*(char)a | (char)A = 97
*(Long)555 ^ (Long)666 = 177
2、論理演算子の演算は短絡形式に従い、ビット演算子はそうではない.短絡とは,いったん演算の結果を特定できると,残りの演算を行わないことである.次の例では、短絡と非短絡の違いをより直感的に示します.
Javaコード
public class OperatorTest { 
    public boolean leftCondition() { 
        System.out.println("  -   :false;  :leftCondition()"); 
        return false; 
    } 
 
    public boolean rightCondition() { 
        System.out.println("  -   :true;  :rightCondition()"); 
        return true; 
    } 
 
    public int leftNumber() { 
        System.out.println("  -   :0;  :leftNumber()"); 
        return 0; 
    } 
 
    public int rightNumber() { 
        System.out.println("  -   :1;  :rightNumber()"); 
        return 1; 
    } 
 
    public static void main(String[] args) { 
        OperatorTest ot = new OperatorTest(); 
 
        if (ot.leftCondition() && ot.rightCondition()) { 
            // do something 
        } 
        System.out.println(); 
 
        int i = ot.leftNumber() & ot.rightNumber(); 
    } 
}

実行結果:
*実行-戻り値:false;方法:leftCondition()
*
*実行-戻り値:0;方法:leftNumber()
*実行-戻り値:1;方法:rightNumber()
運転結果は短絡と非短絡の違いが明らかになったので,この運転結果を生じた原因を分析してみよう.「ot.leftCondition()&&ot.right Condition()」を実行すると、メソッドleftCondition()はfalseを返しますが、「&&」演算では演算子の両方の値がtrueでなければならない場合、演算結果はtrueになりますので、right Condition()の戻り値にかかわらず、「ot.leftCondition()&&ot.right Condition()」の演算値はfalseであると判断でき、論理演算子は短絡的な形式であるため、この場合right Condition()メソッドは実行されなくなる.
一方、「ot.leftNumber()&ot.rightNumber()」については、「leftNumber()」の戻り値が0であるため、ビット演算子「&」にとって演算子の両方の値が1でなければならない場合、演算結果は1であるため、「rightNumber()」方法の戻り値がいくらであるかにかかわらず、「ot.leftNumber()&ot.rightNumber()」の演算結果は0であることが判明しているしかしビット演算子は非短絡であるためrightNumber()メソッドは実行される.これが短絡と非短絡の違いです.
シフト演算子
シフト演算子はビット単位演算子と同様にビット演算子に属するため、シフト演算子のビットもバイナリビットを指す.次のようなものがあります.
1、左シフト(<<):オペレータの左側のオペランドをオペレータの右側に指定した桁数だけ左に移動します.移動のルールは、バイナリの下位で0を補うことです.
2、符号付き右シフト(>>):オペレータの左側のオペランドをオペレータの右側に指定した桁数だけ右に移動します.移動のルールは、被操作数の記号が正であれば、バイナリの高位で0を補うことである.被オペランドの符号が負であれば、バイナリの上位で1を補う.
3、符号なし右シフト(>>>>):オペレータの左側のオペランドをオペレータの右側に指定した桁数だけ右に移動します.移動のルールは,被操作数の符号が正であれ負であれ,バイナリビットの上位に0を補うことである.
なお、シフト演算子には、「符号なし左シフト(<<<)」という説は存在しない.ビット単位演算子と同様に、シフト演算子はbyte、short、int、longなどの整数タイプ、文字列タイプcharに使用できますが、浮動小数点数タイプfloat、doubleには使用できません.もちろん、Java 5.0以降、シフト演算子はbyte、short、int、long、charに対応するパッケージクラスにも使用できます.ビット演算子の例を参照してテストプログラムを書いて検証することができます.ここでは例を挙げません.
ビット単位演算子とは異なり、シフト演算子は短絡的で短絡的でないという問題はありません.
ここまで書くと、面接問題でよく受けた問題に言及せざるを得ません.
参照
ここで最も効率的とは、実際には最小限、最も簡単な演算で所望の結果を得ることであり、シフトはコンピュータにおけるかなりの基礎的な演算であり、それを用いて準を実現することは間違いない.左シフト"<<"は、被操作数を左に1桁ずつ移動させることで、被操作数に2を乗じた効果となり、2*8=(2*2*2*2)は、2を左に3回シフトさせることになる.したがって最も効率的な計算2に8を掛ける方法は「2<<3」である.
次の予告:JAVA面接問題解惑シリーズ(十二)--本当に配列を知っていますか?