私は、クラスを SO スレッドとアークティクルで final にする理由がたくさんあることを読んでいました。その うちの 2 つは
1. To remove extensibility
2. to make class immutable.
クラスを不変にすることは、それと一緒に最終的であるという特徴を持っていますか(それはメソッドです)?2つの違いがわかりませんか?
私は、クラスを SO スレッドとアークティクルで final にする理由がたくさんあることを読んでいました。その うちの 2 つは
1. To remove extensibility
2. to make class immutable.
クラスを不変にすることは、それと一緒に最終的であるという特徴を持っていますか(それはメソッドです)?2つの違いがわかりませんか?
不変オブジェクトでは、状態を変更できません。最終クラスはそれ自体を継承することを許可しません。たとえば、クラスFoo
(以下を参照) は不変 (状態、つまり_name
決して変更されない) であり、クラス Bar は可変 (rename
メソッドで状態を変更できます) です。
final class Foo
{
private String _name;
public Foo(string name)
{
_name = name;
}
public String getName()
{
return _name;
}
}
final class Bar
{
private String _name;
public Bar(string name)
{
_name = name;
}
public String getName()
{
return _name;
}
public void rename(string newName)
{
_name = newName;
}
}
型を「検証可能なほど深く不変」であると認識すると便利な場合があります。つまり、(1) インスタンスが構築されると、そのプロパティはまったく変更されないこと、および (2) それが保持するすべてのオブジェクト インスタンスが静的解析によって示されることを意味します。参照は検証可能なほど深く不変です。静的アナライザーは、可変サブクラスが作成される可能性があるかどうかを知る方法がなく、その可変サブクラスへの参照が、検証可能な深さで不変オブジェクトであるはずのオブジェクト内に格納されているため、拡張に対してオープンなクラスは、検証可能なほど深く不変ではありません。
一方、完全に不変であると指定された抽象 (したがって拡張可能な) クラスを使用すると便利な場合があります。抽象クラスには、派生クラスを強制的に不変にする方法はありませんが、可変派生クラスはすべて「壊れている」と見なす必要があります。この状況は、互いに「等しい」と報告する 2 つのオブジェクト インスタンスが同じハッシュ コードを報告する必要があるという要件に多少似ています。その要件に違反するクラスを設計することは可能ですが、結果として生じる誤ったハッシュ テーブルの動作は、ハッシュ テーブルではなく、壊れたハッシュ コード関数のせいです。
たとえば、特定の (行、列) 位置にある要素を読み取るメソッドを持つ抽象 ImmutableMatrix プロパティがあるとします。考えられる実装の 1 つは、N*M 要素の配列を使用して NxM ImmutableMatrix をサポートすることです。一方、ImmutableDiagonalMatrix のようないくつかのサブクラスを N 要素の配列で定義すると便利な場合があります。ここでValue(R,C)
、R!=C の場合は 0 になります。Arr[R]
R==C の場合。使用している配列のかなりの部分が対角配列である場合、そのようなインスタンスごとに多くのメモリを節約できます。クラスを拡張可能のままにしておくと、誰かがそれを変更可能な方法で拡張する可能性が残されますが、プログラムが使用する配列の多くが特定の形式に適合することを知っているプログラマーが、特定の形式に適合する可能性も残されます。そのフォームを最適に格納するクラスを設計します。