4

私はスーパークラスとたくさんのサブクラスを持っています。すべてのサブクラスで同じ名前のフィールドを1つ作成したいのですが、スーパークラスで定義したくないか、少なくともその値を使用したくありません。これは私が今持っているものです

public abstract class Big {

    public String tellMe = "BIG";

    public Big() {}

    public void theMethod() {
        System.out.println ("Big was here: " + tellMe() + ", " + tellMe);
    }
    public String tellMe() {
        return tellMe;
    }
}

public class Little extends Big{

    public String tellMe = "little";
    public Little(){}

    public String tellMe() {
        return "told you";
    }
    public static void main(String [] args) {
        Little l = new Little();
        l.theMethod();
    }
}

Littleを実行すると、これが出力になります

ビッグはここにありました:あなたに言った、ビッグ

tellMeが「BIG」を指しているのに、なぜ「toldyou」が印刷されるのかわかりません。どうして両方が真実になることができますか?

私の問題は、メソッドtellMe()をBigに配置し、変数tellMe(実際に返される)をすべてのサブクラスで定義することです。これを機能させる唯一の方法は、私が書いたように、各サブクラスのtellMe()メソッドを書き直すことです。しかし、それは継承の目的全体を打ち負かしませんか?助けてください

編集:サブクラスでコンストラクターを使用していません。私が欲しいのは、すべてのサブクラスに設定できるフィールドと、それらの値を使用するスーパーのメソッドだけです。すべてのサブクラスがそれを実装しなければならないので、なぜこれが不可能なのか理解できません。それは理にかなっています...これが単に不可能な場合は、私に知らせてください

4

6 に答える 6

6

メソッドとは異なり、フィールドは仮想ではありません。このため、階層内の別のクラスのフィールドと同じ名前のフィールドを宣言することはお勧めできません。で参照されるフィールドtheMethodは常にfromになりBigます(つまり、同じ名前のフィールドを宣言すると、置換クラスのスコープ内にあるときに古いフィールドが非表示になりますが、置換されません)。

1つの解決策は、現在のクラスからフィールドを取得するメソッドをオーバーライドすることです。

フィールドをすべてのクラスのオーバーライドで置き換えtheMethodて、正しい値(またはスーパークラスのフィールドを非表示にするフィールド)を返します。tellMegetTellMe()getTellMe()

于 2012-07-31T16:43:51.097 に答える
2

Big.tellMeのコンストラクタでの値を上書きできますLittle

取り除く:

public String tellMe = "little";

Littleコンストラクターを次のように変更します。

public Little(){
    tellMe = "little";
}

その時点で、あなたも取り除くことができますLittle.tellMe()

于 2012-07-31T16:43:28.823 に答える
2

Javaのドキュメントに記載されているように、スーパークラスフィールドをオーバーライドするのではなく、非表示にします。また、それを行うのは良い考えではないとも述べられています。

したがって、動的ルックアップはメソッドの場合とは異なります。変数がsonクラスから読み取られる場合、「その」フィールド値を取ります。トップクラスでは、もう1つ。

Javaでオーバーライドできるのは動作であるため、メソッドを定義することをお勧めします。

public String tellMe() {
  return "Whatever";
}

サブクラスでオーバーライドして、必要な文字列を返すことができます。

于 2012-07-31T16:53:42.967 に答える
1

Big内でtellMeを定義する代わりに(Bigでその値を定義/使用したくないと言ったので)、Bigで関数を作成できます。

public abstract String tellMeString();

そして、そのように各サブクラスでそれを定義します(リトルの場合):

public String tellMeString()
{
    return "Little";
}

次に、theMethodは以下を実行できます。

System.out.println ("Big was here: " + tellMe() + ", " + tellMeString());

この場合、変数「tellMe」を定義する必要はまったくありません。各サブクラスのtellMeStringをオーバーライドして、異なる文字列を返すだけです。

于 2012-07-31T16:47:29.603 に答える
1

期待どおり、フィールドは継承されません。サブクラスからスーパークラスのフィールドにアクセスできます(プライベートでない場合)。ただし、フィールドを「オーバーライド」することはできません。tellMeこれが、スーパークラスで実装されたメソッドで使用される場合Big、同じクラスで定義された変数を使用する理由です。

継承が必要な場合は、メソッドを使用します。たとえば"BIG"、スーパークラスと"little"サブクラスで返されるメソッド「tellMe()」を実装できます。

class Big {
    protected String tellMe() {
        return "BIG";
    }
}
class Little {
    @Override
    protected String tellMe() {
        return "Little";
    }
}

tellMeまたは、コンストラクターで変数を初期化することもできます。

class Big {
    private String tellMe;
    public Big() {
        this("BIG");
    }
    protected Big(String tellMe) {
        this.tellMe = tellMe;
    }
    protected String tellMe() {
        return "BIG";
    }
}
class Little {
    public Little() {
         super("Little");
    }
}

これで「Little」が返されますnew Little().tellMe()。スーパークラスの変数は、オブジェクトの作成時に初期化されました。スーパークラスで定義されたメソッドがこの変数を返しました。

于 2012-07-31T16:47:31.833 に答える
1

メソッドはオーバーライドでき、フィールドは呼び出されたスコープに表示されます。

static class Big {
    String field = "BIG";
    String bark()   { return "(big bark)"; }

    void doIt() {
        System.out.format("field(%s) bark(%s)\n", field,bark());
    }
    void doIt2()    {
        System.out.format("2:field(%s) bark(%s)\n", field,bark());
    }
}

static class Small extends Big {
    String field = "small";
    String bark()   { return "(small bark)"; }
    void doIt2()    {
        System.out.format("2:field(%s) bark(%s)\n", field,bark());
    }
}

public static void main(String... args) {

    Big b = new Big();
    b.doIt();
    b.doIt2();

    Small s = new Small();
    s.doIt();
    s.doIt2();
}

出力は次のとおりです。

field(BIG) bark((big bark))
2:field(BIG) bark((big bark))
field(BIG) bark((small bark))
2:field(small) bark((small bark))

doIt()はBigクラスで定義されているため、常にBigバージョンのフィールドが表示されます。doIt2()はBigで定義されていますが、Smallではオーバーライドされています。Big.doIt2()はフィールドのBigバージョンを認識し、Small.doIt2()バージョンはフィールドのSmallバージョンを認識します。

他の人が指摘しているように、これを行うのはかなり悪い考えです。より良いアプローチは、サブクラスコンストラクターに新しい値を設定するか、オーバーライドされるメソッドを使用することです。

于 2012-07-31T17:34:37.910 に答える