Javaのfinalキーワードの詳細と実例


finalはJavaでメンバー変数、方法、クラス、およびローカル変数を宣言することができます。一旦あなたがfinalとして宣言を引用すると、この参照は変更できなくなります。変数を再初期化しようとすると、コンパイラがコンパイルエラーを報告します。
 finalの意味はさまざまな場面で微妙に違っていますが、全体的には「可変ではない」という意味です。
1.final変数
メンバー変数またはローカル変数(メソッドまたはコードブロック内の変数をローカル変数と呼びます。)に対して宣言したものは、finalと呼ばれます。final変数は常にstaticキーワードと一緒に使用され、定数として使用されます。finalのキーワードで修飾された変数は、一度だけ割り当て操作が可能であり、生存期間内にその値を変更することはできません。
ただし、基本タイプと引用タイプに対しては、finalキーワードの効果には微妙な違いがあります。たとえば:

class Value {
  int v;
  public Value(int v) {
    this.v = v;
  }
}
public class FinalTest {
  final int f1 = 1;
  final int f2;
  public FinalTest() {
    f2 = 2;
  }
  public static void main(String[] args) {
    final int value1 = 1;
    // value1 = 4;
    final double value2;
    value2 = 2.0;
    final Value value3 = new Value(1);
    value3.v = 4;
  }
}
上記の例では、mainメソッドにfinalで修飾されたデータは、value 1に初期値を付与した後、value 1の値を修正することができなくなり、finalキーワードは定数として機能しています。value 2から見られます。final修飾の変数は声明の時に値を与えないことができます。つまり先に声明して、後で価値を与えられます。value 3の時に変数を参照してください。ここではfinal修正参照変数を見ることができます。参照変数の参照は変更できないだけです。つまりvalue 3をもう一つのValueオブジェクトに再参照することはできませんが、参照対象の値は変更できます。
一方、メンバー変数をfinalで修飾する際の微妙な違いを見ました。finalで修飾したデータの値は変えられないので、使う前にメンバー変数に対してすでに分配されていることを確認しなければなりません。したがって、final修飾のメンバー変数については、私たちが持っているのは2つだけです。もう一つはメンバーを宣言する時に与えられた値です。もう一つは構造方法で与えられた値です。この2つのところに初期値を与えなければなりません。
最後に注意したいのは、staticとfinalを同時に使って修飾したメンバーがメモリの中で変更できない記憶空間だけを占めていることです。
2.finalメソッドパラメータ
前に私達は変数が私達自身で作成された場合、final修飾を使って私達は一回だけ値を付けて変数の値を変えないということを示しています。変数がパラメータとして入ってきたら、どのようにしてその値が変わらないことを保証しますか?これはfinalの第二の使い方を使っています。つまり、私達が方法を編纂する時に、パラメータの前にfinalキーワードを追加することができます。これは全体の方法において、パラメータの値を変えることはできません。

public class FinalTest {
  /* ... */
  public void finalFunc(final int i, final Value value) {
    // i = 5;     i  
    // v = new Value();     v  
    value.v = 5; //           
  }
}
3.finalの方法
 finalも方法を声明することができます。方法の前にfinalのキーワードを入れて、この方法を代表して布団類の方法で書き直してはいけません。一つの方法の機能が十分に整っていると考えたら、サブクラスの中で変更が必要でないなら、この方法はfinalであると宣言してもいいです。final法は非final法よりも速いです。コンパイルする時に静的に結合されていますので、動作中に動的に結合する必要がありません。prvateとfinalのキーワードについてはもう一つ連絡があります。これはクラスの中のすべてのprvateの方法が暗黙的にfinalと指定されています。類外でprvateの方法を使うことができないので、カバーできません。次にfinal方法の例を示します。

class PersonalLoan{
  public final String getName(){
    return "personal loan";
  }
}
class CheapPersonalLoan extends PersonalLoan{
  @Override
  public final String getName(){
    return "cheap personal loan"; //compilation error: overridden method is final
  }
}
4.final類
 finalを使って修飾するクラスをfinalといいます。finalクラスの通常の機能は完全で、それらは継承されません。Javaには多くの種類がfinalです。例えば、String、Interger、その他の包装類です。以下はfinalクラスの例です。

 final class PersonalLoan{
  }
  class CheapPersonalLoan extends PersonalLoan{ //compilation error: cannot inherit from final class
5.finalキーワードのメリット
ここでは、finalを使ったキーワードの利点をまとめました。
  • finalのキーワードは性能を向上させました。JVMとJavaアプリケーションはいずれもfinal変数をキャッシュします。
  • final変数は、追加の同期オーバーヘッドを必要とせずに、マルチスレッド環境で安全に共有することができる。
  • はfinalのキーワードを使って、JVMは方法、変数およびクラスを最適化します。
  •        不可変クラスを作成するには、finalキーを使用します。可変クラスではないということは、オブジェクトが作成されたら変更できないということです。Stringは可変ではない種類の代表です。可変ではないクラスは多くの利点があります。例えば、それらのオブジェクトは読み取り専用です。マルチスレッド環境で安全に共有できます。追加の同期オーバーヘッドは不要です。
    6.いくつかの混じりやすい点
    (1)クラスのfinal変数と普通変数の違いは何ですか?
    finalでクラスのメンバー変数に作用する場合、メンバー変数(クラスのメンバー変数に注意してください。ローカル変数は使用前に初期化された賦値を保証するだけです。)は定義時またはコンストラクタで初期化賦値を行わなければなりません。また、final変数は賦値を初期化した後、再割当ができなくなります。
    final変数と普通変数の違いは何ですか?次の例を見てください。
    
    public class Test {
      public static void main(String[] args) {
        String a = "hello2"; 
        final String b = "hello";
        String d = "hello";
        String c = b + 2; 
        String e = d + 2;
        System.out.println((a == c));
        System.out.println((a == e));
      }
    }
    
    出力結果:
    true
    false
     まずこの問題の出力結果を考えてもいいです。なぜ最初の比較結果はtrueで、二つ目の比較結果はfasleです。この中はfinal変数と普通変数の違いです。final変数が基本データタイプとStringタイプの場合、コンパイル中にその正確な値が分かります。コンパイラはコンパイル期間の定数として使用します。つまり、このfinal変数を使うところは、直接アクセスするこの定数に相当し、実行時に決定する必要はありません。このようなC言語のマクロ置換とは似ています。したがって、上記のコードのうち、変数bはfinalによって修飾されるので、コンパイラ定数として扱われるので、bに使用される場所で直接変数bをその値に置き換えることができます。変数dへのアクセスは、実行時にリンクで行う必要があります。その違いはよく分かりますが、コンパイルの間にfinal変数の値を正確に知ることができる場合だけ、コンパイラはこのような最適化を行います。たとえば、下記のコードは最適化されません。
    
    public class Test {
      public static void main(String[] args) {
        String a = "hello2"; 
        final String b = getHello();
        String c = b + 2; 
        System.out.println((a == c));
      }
      public static String getHello() {
        return "hello";
      }
    }
    このコードの出力結果はfalseです。
    (2)finalで修飾された参照変数が指すオブジェクトの内容は可変ですか?
     上記のfinalで修飾された参照変数は、賦値を初期化すると他のオブジェクトに向けられなくなりますが、その参照変数が指すオブジェクトの内容は可変ですか?この例を見てください。
    
    public class Test {
      public static void main(String[] args) {
        final MyClass myClass = new MyClass();
        System.out.println(++myClass.i);
      }
    }
    class MyClass {
      public int i = 0;
    }
    このコードはうまくコンパイルできます。出力結果は1です。これは参照変数がfinalによって修飾された後、他のオブジェクトを指すことはできないが、オブジェクトの内容は可変であることを示している。
    (3)finalとstatic
    多くの場合、staticとfinalのキーワードを混同しやすくなります。staticはメンバー変数としてコピーを1つだけ保存することを表します。finalの役割は変数が可変しないことを保証します。この例を見てください。
    
    public class Test {
      public static void main(String[] args) {
        MyClass myClass1 = new MyClass();
        MyClass myClass2 = new MyClass();
        System.out.println(myClass1.i);
        System.out.println(myClass1.j);
        System.out.println(myClass2.i);
        System.out.println(myClass2.j);
      }
    }
    class MyClass {
      public final double i = Math.random();
      public static double j = Math.random();
    }
     このコードを実行すると、各プリントのj値は同じであり、iの値は異なることが分かります。ここからfinalとstatic変数の違いが分かります。
    7.まとめ
    finalに関する重要な知識点は以下の通りです。
    finalキーは、メンバー変数、ローカル変数、方法、およびクラスに使用できます。
    finalメンバー変数は声明の時に初期化またはコンストラクタで初期化しなければなりません。
    あなたはfinal変数に再び値を付けることができません。
    ローカル変数は宣言時に割り当てられます。
    匿名クラスにおけるすべての変数はfinal変数でなければなりません。
    final方法は書き換えられません。
    final類は引き継がれません。
    finalのキーワードはfinallyのキーワードとは異なり、後者は異常処理に用いられる。
    finalキーワードはfinalize()方法と混同しやすいです。後者はObject類で定義された方法で、ゴミ回収前にJVMに呼び出される方法です。
    インターフェースで宣言されているすべての変数自体がfinalです。
    finalとabstractの二つのキーワードは逆関連であり、final類はabstractの可能性がない。
    final法はコンパイル段階で結合されており,静的結合と呼ばれている。
    宣言時にfinal変数を初期化していないものを空白final変数と呼びます。それらはコンストラクタで初期化しなければなりません。またはthis()を呼び出して初期化します。そうしないとコンパイラが「final変数(変数名)を初期化する必要があります」とエラーします。
    クラス、方法、変数をfinalとして宣言し、性能を向上させることができます。このようにJVMは見積もりを行い、最適化する機会があります。
    Javaコードの慣例によれば、final変数は定数であり、通常の定数名は大文字である:
    
    private final int COUNT = 10;
    集合対象宣言については、finalは参照が変更されないことを意味しますが、追加、削除、または変更ができます。例えば:
    
    private final List Loans = new ArrayList();
    list.add(“home loan”); //valid
    list.add("personal loan"); //valid
    loans = new Vector(); //not valid
    以上は小编が绍介したJava中finalのキーワードの详しい解と実例の统合で、皆さんに役に立つことを望んでいます。ここでも私たちのサイトを応援してくれてありがとうございます。