web-dev-qa-db-ja.com

JavaファイナルとC ++ const

Java for C++プログラマーチュートリアル は次のように述べています(強調は私自身のものです):

キーワードfinalは、C++のconstと同等のroughlyです。

この文脈で「大体」とはどういう意味ですか?彼らはまったく同じではありませんか同じですか?

違いはありますか?

143
WinWin

C++では、メンバー関数にconstマークを付けることは、constインスタンスで呼び出せることを意味します。 Javaにはこれに相当するものはありません。例えば。:

class Foo {
public:
   void bar();
   void foo() const;
};

void test(const Foo& i) {
   i.foo(); //fine
   i.bar(); //error
}

値は、後でJavaのみで割り当てられます。例:

public class Foo {
   void bar() {
     final int a;
     a = 10;
   }
}

javaでは合法ですが、C++では合法ではありません。

public class Foo {
   void bar() {
     final int a;
     a = 10;
     a = 11; // Not legal, even in Java: a has already been assigned a value.
   }
}

JavaとC++の両方のメンバー変数は、それぞれfinal/constになります。これらには、クラスのインスタンスの構築が完了するまでに値を与える必要があります。

Javaでは、コンストラクターが終了する前に設定する必要があります。これは、次の2つの方法のいずれかで実現できます。

public class Foo {
   private final int a;
   private final int b = 11;
   public Foo() {
      a = 10;
   }
}

C++では、初期化リストを使用してconstメンバーに値を与える必要があります。

class Foo {
   const int a;
public:
   Foo() : a(10) {
      // Assignment here with = would not be legal
   }
};

Javaではfinalを使用して、オーバーライドできないものとしてマークできます。 C++(C++ 11より前)はこれを行いません。例えば。:

public class Bar {
   public final void foo() {
   }
}

public class Error extends Bar {
   // Error in Java, can't override
   public void foo() {
   }
}

しかし、C++では:

class Bar {
public:
   virtual void foo() const {
   }
};

class Error: public Bar {
public:
   // Fine in C++
   virtual void foo() const {
   }
};

メンバー関数constをマークするセマンティクスが異なるため、これは問題ありません。 (オーバーロードは、メンバー関数の1つにconstのみを指定することでも可能です(C++ 11ではメンバー関数に最終マークを付けることができます。C++ 11更新セクション)


C++ 11アップデート:

実際には、C++ 11では、クラス関数とメンバー関数の両方をfinalとしてマークすることができます。たとえば、Javaの同じ機能と同じセマンティクスを使用できます。

public class Bar {
   public final void foo() {
   }
}

public class Error extends Bar {
   // Error in Java, can't override
   public void foo() {
   }
}

C++ 11で次のように正確に記述できるようになりました。

class Bar {
public:
  virtual void foo() final;
};

class Error : public Bar {
public:
  virtual void foo() final;
};

G ++ 4.7のプレリリースでこの例をコンパイルする必要がありました。この場合、これはconstに置き換わるものではなく、最も近い同等のC++キーワードでは見られなかったJavaライクな動作を提供するものであることに注意してください。したがって、メンバー関数をfinalconstの両方にする場合は、次のようにします。

class Bar {
public:
  virtual void foo() const final;
};

(ここでconstfinalの順序が必要です)。

以前は、constメンバー関数に直接対応するものはありませんでしたが、コンパイル時にエラーを発生させることはありませんが、関数をvirtual以外にすることは潜在的なオプションです。

同様に、Java:

public final class Bar {
}

public class Error extends Bar {
}

c ++ 11になります:

class Bar final {
};

class Error : public Bar {
};

(以前はprivateコンストラクターがおそらくC++でこれに到達するのに最も近いものでした)

興味深いことに、C++ 11以前のコードとの後方互換性を維持するために、finalis n'tは通常の方法でキーワードです。 (ささいで合法なC++ 98の例struct final;を使用して、キーワードにするとコードが壊れる理由を確認してください)

183
Flexo

Javaでは、最後のキーワードを次の4つの目的に使用できます。

  • クラスまたはメソッドでそれを封印する(サブクラス/オーバーライドは許可されない)
  • メンバー変数で宣言することは、それが正確に一度だけ設定できることです(これはあなたが話していることだと思います)
  • メソッドで宣言された変数で、一度だけ設定できることを確認する
  • メソッドパラメータで、メソッド内で変更できないことを宣言する

1つの重要なことは:Java最終メンバー変数mustを一度だけ設定してください!たとえば、コンストラクター、フィールド宣言、または初期化子。 (ただし、メソッドに最終メンバー変数を設定することはできません)。

メンバー変数をfinalにする別の結果はメモリモデルに関連します。これは、スレッド環境で作業する場合に重要です。

29
Ralph

constオブジェクトはconstメソッドのみを呼び出すことができ、一般に不変と見なされます。

const Person* person = myself;
person = otherPerson; //Valid... unless we declared it const Person* const!
person->setAge(20); //Invalid, assuming setAge isn't a const method (it shouldn't be)

finalオブジェクトを新しいオブジェクトに設定することはできませんが、不変ではありません-setメソッドの呼び出しを妨げるものは何もありません。

final Person person = myself;
person = otherPerson; //Invalid
person.setAge(20); //Valid!

Javaには、不変オブジェクトを宣言する固有の方法がありません。クラスを不変として自分で設計する必要があります。

変数がプリミティブ型の場合、final/constは同じように機能します。

const int a = 10; //C++
final int a = 10; //Java
a = 11; //Invalid in both languages

Java finalは、プリミティブ値型のC++ constと同等です。

Java参照型では、最後のキーワードはconstポインターと同等です...

//Java
final int finalInt = 5;
final MyObject finalReference = new MyObject();

//C++
const int constInt = 5;
MyObject * const constPointer = new MyObject();
12
James Schek

ここにはすでにいくつかの素晴らしい答えがありますが、追加する価値があると思われる1つのポイント:C++のconstは、プログラムの他の部分がオブジェクトの状態を変更するのを防ぐためによく使用されます。指摘されているように、Javaのfinalはこれを行うことができません(プリミティブを除く)-referenceが別のオブジェクトに変更されるのを防ぐだけです。ただし、Collectionを使用している場合は、静的メソッドを使用してオブジェクトの変更を防ぐことができます

 Collection.unmodifiableCollection( myCollection ) 

これは、要素への読み取りアクセスを提供するCollection参照を返しますが、変更が試行されると例外をスローし、C++のconstのようになります

8
pocketdora

Javaのfinalは、プリミティブ型と参照に対してのみ機能し、constキーワードが何かに機能するオブジェクトインスタンス自体には機能しません。

const list<int> melist;final List<Integer> melist;を比較すると、最初のリストではリストの変更が不可能になりますが、後者では新しいリストをmelistに割り当てることができません。

7
josefx

特定の 微妙なマルチスレッドプロパティ のほかに、宣言された変数finalは宣言時に初期化する必要はありません!

つまり、これはJavaで有効です:

// declare the variable
final int foo;

{
    // do something...

    // and then initialize the variable
    foo = ...;
}

C++のconstで記述した場合、これは無効になります。

3
antak

wikipedia によると:

  • C++では、constフィールドは再割り当てから保護されるだけでなく、constメソッドのみを呼び出すことができ、他のメソッドのconst引数としてのみ渡すことができるという追加の制限があります。
  • 非静的内部クラスは、包含クラスのどのフィールドにも、finalかどうかに関係なく自由にアクセスできます。
2
KevenK

C++のconstの意味は、ポインター、つまり定数ポインターと定数オブジェクトへのポインターについて話すと複雑になるため、「大体」と言っていると思います。 Javaには「明示的な」ポインターがないため、finalにはこれらの問題はありません。

2
Dima

Switch/caseステートメントの例で理解したことを説明しましょう。

各caseステートメントの値は、switch値と同じデータ型のコンパイル時定数値でなければなりません。

以下のようなものを宣言します(メソッド内でローカルインスタンスとして、またはクラス内で静的変数として(静的に追加します))、またはインスタンス変数として宣言します。

final String color1 = "Red";

そして

static final String color2 = "Green";

switch (myColor) { // myColor is of data type String
    case color1:
    //do something here with Red
    break;
    case color2:
    //do something with Green
    break;
}

color1がローカル変数ではなくクラス/インスタンス変数である場合、このコードはコンパイルされません。これは、color1がstatic finalとして定義されている場合にコンパイルされます(その後、static final変数になります)。

コンパイルされない場合、次のエラーが表示されます

error: constant string expression required
0
Subbu Mahadevan