Javaオブジェクト向けプログラミングにおけるfinalキーワードの使用方法の詳細

4821 ワード

Javaでfinalキーワードでオブジェクトに不変性(immutable)があることを宣言します.ここでのオブジェクトには変数、メソッド、クラスが含まれており、C++のconstキーワード効果と似ています.immutableとは、オブジェクトが作成された後、状態が変更できない場合にfinalキーワードを使用することを3つの角度から考慮することを意味します.
  • コード自体:final記述を望まないオブジェクトが表現する意味が
  • に変更される.
  • セキュリティ:finalオブジェクトは読み取り専用プロパティを持ち、スレッドセキュリティの
  • です.
  • 効率:finalオブジェクト自体を変更できず、参照操作がより効率的です.
    final変数はfinal Object aを定義し、aは一度だけ初期化され、一度初期化するとaのデータは変更されず、aが参照タイプであれば他のオブジェクトを再バインドすることはできません.初期化されていないfinal変数はblank finalと呼ばれ、メンバー変数の場合は初期化またはコンストラクタに値を割り当てる必要があります.例:
    
    class Circle {
     static final double PI = 3.1415926;
     final int radius = 5;
     final int xPos;
     final int yPos;
     public Circle(int x, int y) {
     xPos = x; 
     yPos = y;
     }
    }
    

    finalメソッドはfinal methodを定義し、メソッドは再ロードできません.メソッド設計者は、メソッドの再ロードによって他の関連機能に異常が発生することを望んでいません.例:
    
    class BaseClass {
     public final void method() {}
    }
    
    class DerivedClass extends BaseClass {
     public final void method() {} //     
    }
    
    

    なお、finalメソッドの定義は必ずしもinlineの効果を生み出すとは限らない.なぜなら、メソッドがinlineであるかどうかは、finalキーワードではなくJVMのポリシーに依存し、finalの設計によってメソッドの効率を向上させることは正確ではないからである.
    finalクラスfinal class X定義のクラスXは継承できません.JavaではStringクラスがfinalとして設計され,その定義は以下の通りである.
     
      
    public class final String extends Object  implements Serializable, Comparable, CharSequence

    なぜStringはfinalに設計されたのですか?
  • Stringクラスのインスタンスが初期化された後、スタック上の内容は変更できません.Stringクラスが提供するStringオブジェクトを変更する方法はすべて新しいStringオブジェクトを生成することができ、Stringの操作を大幅に簡略化し、コードが読みやすく、理解しやすいです.
  • String finalはString interningを実現する(メモリ内の異なるstring値は1部のみ)の必要条件は、通常、コードに多数のStringオブジェクトが存在するため、異なる参照は同じ文字列空間を指し、Stringがfinalでない場合、1つの文字列空間の内容が変更されると、すべての参照がこの状況を知る必要があるため、このメカニズムの実現は非常に複雑であり、効率に影響を与えるに違いない..String interningはメモリスペースを節約し、時間と費用を節約することができます.
  • String読み取り専用であれば、非常に重要な内容が改ざんされる心配はありません.

  • 内部クラスとfinalが1つのメソッド内で匿名の内部クラスを定義する場合、内部クラスはメソッド内のfinalタイプ変数にのみアクセスでき、Javaコンパイラが変数の値を事前にキャプチャし、内部クラスにコピーを保存することができ、メソッドが破棄されると、内部クラスのメモリ空間は依然として完全になります.例:
    
    public class Wrapper {
    
      public static void main(String[] args) {
       
        // Object obj = null; //    
        final Object obj = null;
        new Thread(new Runnable() {
         public void run() {
         obj = "hello";
         }
        }).start();
      }
    }
    
    

    PS:内部匿名クラスが外部の非final変数にアクセスできないという問題は少し拗ねて聞こえますが、実はJava内部クラスの特性をもっと話したいのです.
    この問題を思い出すのは、最近JDKソースのHTTP keepaliveに関するコードを読んだとき、ソースファイルsunの1つである.net.www.protocol.http.HttpURLConnection.JAvaは何気なく次のコードを見ました.
    
    final boolean result[] = {false};
    java.security.AccessController.doPrivileged(new java.security.PrivilegedAction() {
      public Object run() {
        try {
          InetAddress a1 = InetAddress.getByName(h1);
          InetAddress a2 = InetAddress.getByName(h2);
          result[0] = a1.equals(a2);
        } catch (UnknownHostException e) {
        } catch (SecurityException e) {
        }
        return null;
      }
    });
    
    return result[0];
    
    

    Javaの匿名内部クラスは、対応する関数の非final変数にアクセスできません.外部のlocal variableにアクセスするには、このvariableをfianlとして定義する必要がありますが、finalとして定義すると匿名内部クラスでこの変数の値を変更することはできませんので、匿名内部クラスが役に立つ値を返すのは容易ではありません.このコードは非常に巧みな方法を使用しています.ここでは配列を使用してこの制限を迂回します.resultという変数の参照を変更することはできませんが、resultが指す配列の内容を変更することができます.
    内部匿名クラスが外部変数を修正する小さなテクニックを記録したいだけです.しかし、ここまで来た以上、内部クラスにどのような特性や制限があるかを見続けてみましょう.
    本文を続ける前に、本文に関連するJava用語を明確にする必要があると思います.これらの用語は中国語に翻訳しにくいので、英語で説明します.
    
    // This is class
    public class JavaTerm {
    
      // field or member variable
      private int field;
    
      // constructor
      public JavaTerm() {
      }
    
      // method
      public void method() {
    
        // local variable
        int localVariable = 0;
    
        // local class
        class LocalClass {
          public LocalClass() {
          }
        }
        // anonymous class
        new Runnable() {
          public void run() {
          }
        };
      }
    }
    
    

    今日は、inner classに属するlocal classとanonymous classに注目します.
    Javaでは、ネストクラス(nested class)と呼ばれ、nested classはstatic nested class、non-static nested class、inner classの2つに分類できます.inner classはlocal classとanonymous classに分けることができます.
    anonymous classのいくつかの制限
  • anonymous classは、そのクラスを含むクラス変数(field/member variable)
  • にアクセスできます.
  • anonymous classは、finalではないローカル変数(local variable)
  • にアクセスできません.
  • はnested classと同様にanonymous classで定義されたvariableが、この内部クラスを含む役割ドメインの同名のvariable
  • を上書きします.
  • 静的初期化方法を定義することはできません
  • anonymous classには静的メンバー変数があります.このメンバー変数は定数(finalで修飾)でなければなりません.
  • anonymous classは構造関数
  • を持つことはできません.