Java for C++プログラマーチュートリアル は次のように述べています(強調は私自身のものです):
キーワードfinalは、C++のconstと同等のroughlyです。
この文脈で「大体」とはどういう意味ですか?彼らはまったく同じではありませんか同じですか?
違いはありますか?
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では、クラス関数とメンバー関数の両方を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ライクな動作を提供するものであることに注意してください。したがって、メンバー関数をfinal
とconst
の両方にする場合は、次のようにします。
class Bar {
public:
virtual void foo() const final;
};
(ここでconst
とfinal
の順序が必要です)。
以前は、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以前のコードとの後方互換性を維持するために、final
is n'tは通常の方法でキーワードです。 (ささいで合法なC++ 98の例struct final;
を使用して、キーワードにするとコードが壊れる理由を確認してください)
Javaでは、最後のキーワードを次の4つの目的に使用できます。
1つの重要なことは:Java最終メンバー変数mustを一度だけ設定してください!たとえば、コンストラクター、フィールド宣言、または初期化子。 (ただし、メソッドに最終メンバー変数を設定することはできません)。
メンバー変数をfinalにする別の結果はメモリモデルに関連します。これは、スレッド環境で作業する場合に重要です。
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();
ここにはすでにいくつかの素晴らしい答えがありますが、追加する価値があると思われる1つのポイント:C++のconst
は、プログラムの他の部分がオブジェクトの状態を変更するのを防ぐためによく使用されます。指摘されているように、Javaのfinal
はこれを行うことができません(プリミティブを除く)-referenceが別のオブジェクトに変更されるのを防ぐだけです。ただし、Collection
を使用している場合は、静的メソッドを使用してオブジェクトの変更を防ぐことができます
Collection.unmodifiableCollection( myCollection )
これは、要素への読み取りアクセスを提供するCollection
参照を返しますが、変更が試行されると例外をスローし、C++のconst
のようになります
Javaのfinal
は、プリミティブ型と参照に対してのみ機能し、constキーワードが何かに機能するオブジェクトインスタンス自体には機能しません。
const list<int> melist;
とfinal List<Integer> melist;
を比較すると、最初のリストではリストの変更が不可能になりますが、後者では新しいリストをmelist
に割り当てることができません。
特定の 微妙なマルチスレッドプロパティ のほかに、宣言された変数final
は宣言時に初期化する必要はありません!
つまり、これはJavaで有効です:
// declare the variable
final int foo;
{
// do something...
// and then initialize the variable
foo = ...;
}
C++のconst
で記述した場合、これは無効になります。
wikipedia によると:
C++のconst
の意味は、ポインター、つまり定数ポインターと定数オブジェクトへのポインターについて話すと複雑になるため、「大体」と言っていると思います。 Javaには「明示的な」ポインターがないため、final
にはこれらの問題はありません。
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