JAva基本功16課:(5)式の罠

6093 ワード

1.文字列トラップ
1.1 javaオブジェクトを作成する一般的な方法は次のとおりです.
  • new呼び出しコンストラクタによりJavaオブジェクトを作成します.
  • ClassオブジェクトのnewInstance()メソッドを使用してコンストラクタを呼び出してJavaオブジェクトを作成します.
  • Javaの逆シーケンス化メカニズムによってIOストリームからJavaオブジェクトが復元される.

  • Javaオブジェクトのシーケンス化を使用して、オブジェクトを保存するときに、その状態を1組のバイトに保存し、将来的には、これらのバイトをオブジェクトにアセンブリします.オブジェクトのシーケンス化は、オブジェクトの「ステータス」、すなわちそのメンバー変数を保存することに注意してください.したがって、**オブジェクトのシーケンス化はクラス内の静的変数**に注目しないことが分かる.
  • Javaオブジェクトが提供するclone()メソッドを使用して、新しいJavaオブジェクトをコピーします.
  • 文字列、Byte、Short、Integer、Long、Character、Float、Double、Booleanなどの基本的なタイプのパッケージクラスについて.
  • 直接量でjavaオブジェクトを作成する.String str="abc";
  • .
  • 簡単なアルゴリズム式、接続演算によってJavaオブジェクトを作成します.String str2="abc"+"ddd";

  • 1.2 JVMによる文字列の処理
  • String java=new String(" ");この文は実際に2つの文字列オブジェクトを作成し、1つは「私に丶励ましを与える」という直接量に対応する文字列オブジェクトであり、1つはnew String()コンストラクタによって返される文字列オブジェクトである.テストコードは次のとおりです:
  •         String java=new String("     "); 
            //test1
            String test1="     ";
            System.out.println(test1==java); //false        ,   new         
            //test2
            System.out.println(java.intern()==test1); //true intern()             。
           
    
  • 文字列接続式の値がコンパイル時に決定された場合、JVMはコンパイル時に文字列変数の値を計算し、文字列プール内の対応する文字列を指します.すなわち、最初に、これらのアルゴリズム式が文字列直接量、整数直接量であり、変数やメソッドが関与せず、「マクロ置換」(final修飾変数を使用)であれば、コンパイル期間中に文字列の値を決定することができる.変数を使用してメソッドを呼び出すと、文字列式の値を決定するのは実行時まで待たなければなりません.例は、
  •   
            String hello="hello";
            String java="java";
            final String str1Final="java";
            final String str2Final=java;
    
            String str1="hellojava";
            String str2="hello"+"java";   
            String str3=hello+java;
            String str4="hello"+str1Final;
            String str5="hello"+str2Final;
    
            //test
            //      
            System.out.println(str1==str2);  //ture 
            //     
            System.out.println(str1==str3);  //false 
            //   
            System.out.println(str1==str4);  //true 
            //   final       
            System.out.println(str1==str5);  //false
    

    なぜ第二条はfalseなのか、実は理解しなければならない.
          String hello="hello";
          String java="java";
          String str3=hello+java;
          //   :
          String str3=(new StringBuilder().append("hello").append("java").toString());
    

    newは新しいオブジェクトを持っているので、falseに違いありません.逆コンパイル後のコードはこうです
            String s = "hello";
            String s1 = "java";
            String s2 = (new StringBuilder()).append(s).append(s1).toString();
            String s3 = (new StringBuilder()).append("hello").append("java").toString();
    

    なぜ第4条もfalseなのでしょうか?コンパイル期間中に決定された値がないため、このfinalはマクロ置換ではなく、不変の「変数」として扱うしかないので、次は第2の原理と同じです.
  • 文字列比較2文字列が同じかどうかを比較するには==で判断すればよいが、2文字列に含まれる文字列が同じかどうかを判断するには、Stringで書き換えたequals()メソッドで比較すべきであり、コードは以下の通りである:
  •   //r         ,  true
      if(this==anObject){
          retrun true;
    }
    //  anObject String  
    if(anObject instanceof String){
       String anotherString =(String)anObject;
       //n          
       int n=count;
       //            
      if(n==anotherString.count){
        //       ,anotherString         
        char v1[]=value;
        char v2[]=anotherString.value;
       int i =offset;
       int j =anotherString.offset;
       //    v1   v2        
       while(n--!=0){
        if(v1[i++]!=v2[j++])
           return false;
    }
       return true;
    }
         return false;
    }
    

    StringクラスはComparableインタフェースも実現するので、プログラムはStringが提供するcompareTo()メソッドによって2つの文字列の間の大きさを判断することができ、2つの文字列に含まれる文字列が等しい場合、プログラムはcompareTo()比較によって0を返す.
    public int compareTo(String anotherString) {
            int len1 = value.length;
            int len2 = anotherString.value.length;
            int lim = Math.min(len1, len2);
            char v1[] = value;
            char v2[] = anotherString.value;
            int k = 0;
            while (k < lim) {
                char c1 = v1[k];
                char c2 = v2[k];
                if (c1 != c2) {
                    return c1 - c2;
                }
                k++;
            }
            return len1 - len2;
        }
    

    2.式タイプのトラップ
    2.1式のタイプ
  • すべてのbyte、short、charタイプはintタイプ参加演算
  • に昇格する.
  • 算術式全体のデータ型は、式の最高レベルのオペランドと同じタイプに自動的に昇格し、オペランドのレベルは以下のように配列されます.
  • char -> int -> long ->float -> double
  • byte -> short -> int -> long ->float -> double


  • 2.2複合割付演算子
  • 複合代入演算子に含まれる暗黙型変換、例えば
  •    a=a+5;
       a+=5; //       a=(a   )(a+5);
    
  • 複合賦値演算の場合は、「オーバーフロー」に注意し、「オーバーフロー」の場合は、上位「カット」が行われます.たとえば、
  •   short st=5;
      st+=90010;
      System.out.println(st); //    24479
    //   "  ",              ,short    -32768~32767     ,    "  ",         。
    
  • +を文字列接続演算子として使用する場合、+=演算子の左側の変数はStringタイプのみであり、ObjectやCharSequenceなどのStringの親タイプではない.
  • 3.エスケープ文字の罠
  • 文字を慎むUnicodeエスケープ形式
  • 行コメントのエスケープ文字
  • を中止
    4.汎用型によるエラー
    4.1元の型変数の付与
  • プログラムが元のタイプの変数を汎用情報を持つ変数に割り当てる場合、
  • は常にコンパイル(警告情報を提示するだけ)することができる.
  • プログラムが汎用宣言付きの集合の集合要素にアクセスしようとすると、コンパイラは常に集合要素を汎用タイプとして処理する(集合内の集合要素の実際のタイプには関心がない)
  • .
  • プログラムが汎用宣言付き集合の集合要素にアクセスしようとすると、JVMは各集合要素を巡って自動的に強制変換を実行し、集合要素の実際のタイプが集合が持つ汎用情報と一致しない場合、実行時にClassCastException
  • を開始する.
    4.2元のタイプによる消去
  • 汎用情報を持つオブジェクトを別の汎用情報を持たない変数に割り当てると、括弧の間のすべてのタイプ情報が破棄されます.
  • 4.3汎用配列のトラップの作成
  • Javaでは汎用配列の作成は許可されていません
  • 5.正規表現トラップ
    5.1 Stringクラスのいくつかの方法は正規表現をサポートする
  • matches(String regex);文字列が指定した正規表現に一致するかどうかを判断します.
  • String replaceAll(String regex,String replacement)は、文字列内の正規表現に一致するサブ列をreplacementに置き換えて
  • を返します.
  • String replaceFirst(String regex,String replacement)文字列の最初の正規表現に一致するサブ列をreplacementに置き換えて
  • を返します.
  • String[]split(String regex);regex正規表現で一致するサブ列を分割子として文字列
  • を分割する.
    6.マルチスレッドトラップ
    6.1 RUNメソッドを呼び出さない
    オープンスレッドはrun()メソッドではなくstart()メソッドを使用します.
    6.2静的同期方法
    同期コードブロックの場合、プログラムは同期モニタを明示的に指定する必要があります.同期非静的メソッドの場合、このメソッドの同期モニタはthis、すなわちメソッドを呼び出すJavaオブジェクトです.静的同期メソッドの場合、このメソッドの同期モニタはthisではなく、クラス自体です.