私はこの質問を通過しましたJavaでクラス変数をオーバーライドする方法はありますか? 36の賛成票を持つ最初のコメントは次のとおりです。
が表示された場合は
protected static
、実行してください。
誰がなぜprotected static
眉をひそめているのか説明できますか?
final
は、フィールドが不変であることを意味しません。参照変数object
によって参照されるものはいつでも変更できfinal
ます。
私はこの質問を通過しましたJavaでクラス変数をオーバーライドする方法はありますか? 36の賛成票を持つ最初のコメントは次のとおりです。
が表示された場合は
protected static
、実行してください。
誰がなぜprotected static
眉をひそめているのか説明できますか?
final
は、フィールドが不変であることを意味しません。参照変数object
によって参照されるものはいつでも変更できfinal
ます。
回答:
それは直接的な問題というよりは文体的なものです。それはあなたがクラスで何が起こっているのかを適切に考えていなかったことを示唆しています。
static
意味を考えてみてください。
この変数はクラスレベルに存在し、インスタンスごとに個別に存在することはありません。また、私を拡張するクラスに独立して存在することもありません。
protected
意味を考えてみてください。
この変数は、このクラス、同じパッケージ内のクラス、および私を拡張するクラスから見ることができます。
2つの意味は、相互に排他的ではありませんが、かなり近いです。
2つを一緒に使用できる唯一のケースは、拡張するように設計された抽象クラスがあり、拡張クラスが元のクラスで定義された定数を使用して動作を変更できる場合です。このような配置は、おそらく非常に厄介なものになり、クラスの設計の弱点を示しています。
ほとんどの場合、定数をpublicにすると、すべてがよりクリーンになり、サブクラス化の柔軟性が向上するため、より適切です。抽象クラスは継承を強制しますが、多くの場合、他のものとはかなり離れて構成が継承よりも望ましいです。
これがどのように物事を壊すことができるかの1つの例を見て、独立した存在を持たない変数によって私が何を意味するかを説明するには、次の例のコードを試してください。
public class Program {
public static void main (String[] args) throws java.lang.Exception {
System.out.println(new Test2().getTest());
Test.test = "changed";
System.out.println(new Test2().getTest());
}
}
abstract class Test {
protected static String test = "test";
}
class Test2 extends Test {
public String getTest() {
return test;
}
}
結果が表示されます。
test
changed
https://ideone.com/KM8u8Oで試してみてください
このクラスは、Test2
静的メンバにアクセスすることが可能であるtest
から、Test
名前を修飾する必要なし-しかし、それは継承しないか、独自のコピーを取得します。メモリ内のまったく同じオブジェクトを調べています。
Rectangle
)を調整して幅/高さを調整して()が等しくなるようにするSquare
と、望ましくない結果が生じます。
それは矛盾しているのでそれは眉をひそめています。
変数を作成するprotected
と、パッケージ内で使用されるか、サブクラス内で継承されることになります。
変数static
を作成すると、変数がクラスのメンバーになり、継承する意図がなくなります。これは、パッケージ内で使用する意図のみを残し、私たちはそれpackage-private
をします(修飾子はありません)。
あなたはJavaFXののようなアプリケーションを(起動するために使用されなければならないクラスを宣言した場合、私はこの便利を見つけることができる唯一の状況がありApplication#launch
、そして唯一のサブクラスから起動できるようにしたかった。そうする場合は、この方法でもあることを確認final
します不許可隠れる。しかし、これは「当たり前」ではない、おそらく打ち上げアプリケーションへの新しい方法を追加することによって、より複雑にすることを防止するために実装されました。
各修飾子のアクセスレベルを確認するには、次を参照してください。Javaチュートリアル-クラスのメンバーへのアクセスの制御
static
それを継承する意図をどのように排除するのか私にはわかりません。別のパッケージの私のサブクラスはprotected
、それがアクセスするために、スーパーのフィールドにアクセスする必要があるためですstatic
。package-private
助けられない
protected static
。しかし、それはコードのにおいなので、「実行」の部分です。アクセス修飾子と継承は2つの異なる主題です。はい、そうであれば、スーパークラスから静的メンバーにアクセスすることはできませんpackage-private
。ただしstatic
、そもそも継承に依存してフィールドを参照するべきではありません。それは貧弱なデザインのしるしです。static
メソッドをオーバーライドしようとしても結果が得られないことがわかります。これは、継承がクラスベースではないことを明確に示しています。クラスまたはパッケージの外からアクセスする必要がある場合は、次のようにする必要がありますpublic
private static
最初はいくつかのutil関数を含むクラスがありますが、誰かが私のクラスから改善またはカスタマイズしたいと思うかもしれません。これらのutil関数もそれらに便利を提供するかもしれません。public
utilメソッドは私のクラスのインスタンスのユーザー向けではないため、適切ではない可能性があります。代わりに良いデザインを理解するのを手伝ってくれませんprotected
か?ありがとう
これが眉をひそめられるべきである特定の理由を私は見ません。同じ動作を実現する代替手段は常に存在する可能性があり、これらの代替手段が保護された静的メソッドよりも「優れている」かどうかは、実際のアーキテクチャに依存します。しかし、保護された静的メソッドが妥当である1つの例は、少なくとも次のとおりです。
(protected
明確に使用できるように、個別のパッケージに分割するように編集されています)
package a;
import java.util.List;
public abstract class BaseClass
{
public Integer compute(List<Integer> list)
{
return computeDefaultA(list)+computeDefaultB(list);
}
protected static Integer computeDefaultA(List<Integer> list)
{
return 12;
}
protected static Integer computeDefaultB(List<Integer> list)
{
return 34;
}
}
それから派生:
package a.b;
import java.util.List;
import a.BaseClass;
abstract class ExtendingClassA extends BaseClass
{
@Override
public Integer compute(List<Integer> list)
{
return computeDefaultA(list)+computeOwnB(list);
}
private static Integer computeOwnB(List<Integer> list)
{
return 56;
}
}
別の派生クラス:
package a.b;
import java.util.List;
import a.BaseClass;
abstract class ExtendingClassB extends BaseClass
{
@Override
public Integer compute(List<Integer> list)
{
return computeOwnA(list)+computeDefaultB(list);
}
private static Integer computeOwnA(List<Integer> list)
{
return 78;
}
}
protected static
修飾子は確かにここに正当化することができます。
static
インスタンス変数に依存しないため、にすることができます。これらは、ポリモーフィックメソッドとして直接使用するためのものではなく、より複雑な計算の一部であるデフォルトの実装を提供し、実際の実装の「ビルディングブロック」として機能する「ユーティリティ」メソッドです。public
実装の詳細であるため、にしないでください。そして、それらはprivate
、拡張クラスによって呼び出されるべきなので、そうすることはできません。また、他のパッケージの拡張クラスからアクセスできないため、「デフォルト」の可視性を持つこともできません。(編集:元のコメントはメソッドではなくフィールドのみを参照していたと想定できますが、それでは一般的すぎます)
protected final
(それらをオーバーライドしたくないため)ではなく、として定義する必要がありますstatic
。メソッドがインスタンス変数を使用しないという事実は、それがそうである必要があることを意味しませんstatic
(それは可能ですが)。
final
は対照的に、メソッドがオーバーライドされることを意図していないことが明確になるだけでなく、メソッドがインスタンス変数を使用しないことも読者に明確になります。だから簡潔に言うと、それを静的にしない理由はありません。
protected
継承を示すためではなく、単一のパッケージの下に保持するために何かを作成する場合もあります-公開されません。密封されたインターフェースは、Javaでこのようになるとこのように役立つと思います
protected
「クラスを継承する(異なるパッケージでも)」...を
静的メンバーは継承されず、保護されたメンバーはサブクラス(もちろん、それを含むクラス)にのみ表示されるため、protected static
はと同じようstatic
に表示され、コーダーによる誤解を示唆しています。
protected
、同じではありません。とだけ言うstatic
と、フィールドは同じパッケージ内のサブクラスにのみ表示されます。
protected static
使用すると、パッケージ内またはサブクラスからアクセスできます。変数を静的にすると、サブクラス化の意図がなくなり、パッケージ内からのアクセスのみが意図されます。
まあ、ほとんどの人が答えたように:
protected
つまり、「package-private +サブクラスへの可視性-プロパティ/動作は継承されます」static
意味-「インスタンスの反対-クラスのプロパティ/動作です。つまり、継承されません」したがって、それらは少し矛盾しており、互換性がありません。
しかし、最近、私はこれら2つを一緒に使用することが理にかなっているかもしれないユースケースを思いつきました。不変の型のabstract
親であり、サブタイプに共通の一連のプロパティを持つクラスを作成するとします。不変性を適切に実装し、読みやすさを維持するために、ビルダーパターンを使用することができます。
package X;
public abstract class AbstractType {
protected Object field1;
protected Object field2;
...
protected Object fieldN;
protected static abstract class BaseBuilder<T extends BaseBuilder<T>> {
private Object field1; // = some default value here
private Object field2; // = some default value here
...
private Object fieldN; // = some default value here
public T field1(Object value) { this.field1 = value; return self();}
public T field2(Object value) { this.field2 = value; return self();}
...
public T fieldN(Object value) { this.fieldN = value; return self();}
protected abstract T self(); // should always return this;
public abstract AbstractType build();
}
private AbstractType(BaseBuilder<?> b) {
this.field1 = b.field1;
this.field2 = b.field2;
...
this.fieldN = b.fieldN;
}
}
そしてなぜprotected static
?AbstactType
独自の非抽象ビルダーを実装し、外部package X
に配置され、にアクセスして再利用できる非抽象サブタイプが必要だからですBaseBuilder
。
package Y;
public MyType1 extends AbstractType {
private Object filedN1;
public static class Builder extends AbstractType.BaseBuilder<Builder> {
private Object fieldN1; // = some default value here
public Builder fieldN1(Object value) { this.fieldN1 = value; return self();}
@Override protected Builder self() { return this; }
@Override public MyType build() { return new MyType(this); }
}
private MyType(Builder b) {
super(b);
this.fieldN1 = b.fieldN1;
}
}
もちろん、BaseBuilder
公開することはできますが、それから別の矛盾する声明に行きます。
したがって、with protected static
とのpublic
ビルダーのabstract class
両方で、矛盾するステートメントを組み合わせます。それは個人的な好みの問題です。
ただし、OODとOOPの世界では不自然に感じるので、私はまだのpublic
ビルダーをabstract class
好みprotected static
ます!
final
。クラス間で共有される変更可能な静的フィールドは、間違いなく心配の種です。静的フィールドを更新する複数のクラスは、信頼性が高くない、または追跡が容易ではない可能性があります。特に、保護されたフィールドまたはメソッドの存在は、クラスが他のパッケージのクラスによって拡張されることを意味しているため、おそらく保護されたフィールドを含むクラスの作成者。