14

抽象クラスがあり、実装に基づいてすべてのサブクラスに定数を定義してもらいます。これは主に、クラスの実装に関するメタデータです。

スーパークラスでは:

protected static final String OBJECT_NAME;
protected static final String OBJECT_DEF;

そして、サブクラスで:

protected static final String OBJECT_NAME = "awesome class";
protected static final String OBJECT_DEF = "an awesome class that is also great";

クラスの実装に定数を宣言させる方法はありますか?

4

6 に答える 6

12

サブクラスに、そのクラスの定数となるメソッドを定義させることができます。

protected abstract String objectName();
protected abstract String objectDef();

注:サブクラスのサブクラスがある場合、これらはこれらのメソッドをオーバーライドすることを「忘れる」可能性があります。

于 2012-08-10T07:17:12.677 に答える
1

これはそのようには機能しません。私はこれらを抽象的な関数として定義します:

protected abstract String objectName();
protected abstract String objectDef();

そしてサブクラスでは:

private static final String OBJECT_NAME = "awesome class";
private static final String OBJECT_DEF = "bla";

protected String objectName(){
    return OBJECT_NAME;
}

protected String objectDef(){
    return OBJECT_DEF;
}

方法はstatic違いますが、これがあなたが望むものに到達できる最も近い方法だと思います。

于 2012-08-10T07:24:26.637 に答える
1

スーパークラスの適切なデフォルトがないため、インターフェイスを使用することもできます。

interface HasObjectNameAndDef {
    public String getObjectName();
    public String getObjectDef(); 
}

次に、実際のクラスにインターフェースを実装してもらいます。ボーナスとして、より柔軟なテストが受けられます。

于 2012-08-10T07:39:26.813 に答える
1

これが別のアプローチです。厳密で、ほとんどのコード(ゲッターを含む)を親クラスに配置して、サブレーザーをきちんと残しておくことができるので、私はそれが好きです。

abstract class Parent {
    private final int age;
    private final String name;

    Parent(int age, String name) {
        this.age = age;
        this.name = name;
    }

    int getAge() {
        return age;
    }
}

class Child extends Parent {

    Child() {
        super(18, "John");
        // any other Child specific constructor logic
    }
}

class Main {
    public static void main(String[] args) {
        var child = new Child();
        System.out.println(child.getAge()); // Will print 18
    }
}

注:のコンストラクターをChild継承しないためParent、を初期化するときに誤ってwearedコンストラクターを使用する危険はありませんChild

于 2020-03-03T13:29:53.303 に答える
0

いいえ、できません。

抽象スーパークラスでconstantを宣言するには、具体的な値を割り当てないでください。それ以外の場合は、エラーが発生します。最終フィールドは、宣言中またはクラスコンストラクターで初期化する必要があります。

変数を初期化する抽象メソッドを宣言できます(ただし、これはさらにわかりにくくなります)。このような:

protected String OBJECT_NAME = getObjectNameValue();

public abstract String getObjectNameValue();

ただし、そのような場合、変数とメソッドは静的であってはなりません。静的メソッドを抽象として定義することはできないためです(説明についてはこちらをご覧ください)。

または、Peter Lawreyが提案した変数の代わりにメソッドを直接使用することもできます。これにより、読みやすくなります。

于 2012-08-10T07:13:11.893 に答える
-1

私はあなたが言っていることを知っています。

たとえば、インターフェイス(ExecutableListと呼んでいます)に、次のような定数文字列フィールドを設定したいとします。USER_FRIENDLY_NAME

public interface ExecutableList<T extends ExecutableList<T,E>,E> //This is type parameter
    extends List<E>,                                             //self referencing. Trust
            Comparable<E>,                                       //me, it has its uses.
{
  /** This would declare a constant but leave it to sub-interfaces/classes to define it. */
  abstract String USER_FRIENDLY_NAME;

  //Define the rest of your interface

}

残念ながら、これはJavaでは不可能です。Javaインターフェースでフィールドを宣言する場合、それは修飾子、、、およびを意味publicstaticますfinal。Javaプログラミング言語への将来の変更により、abstract追加が可能になる可能性があります。これにより、暗黙の修飾子public abstract static final String USER_FRIENDLY_NAME;が作成されますが、このためのルールを明確に定義できますが、通常、反対の意味を定義すると理解されているため、この単語の使用はabstract混乱を招きます。abstractfinal

私は、Javaの将来のバージョンがこれを実装することを考えています。プライベートインターフェイスメソッドがJava9で追加されると聞きましたが(デフォルトのメソッド間で使用するため)、この言語への追加についてはまだ何も語られていません。最初に考慮すべき後方互換性の問題がいくつかあると思います。Oracleの誰かがこれを読んだら、インターフェイスの定数を宣言し、継承するクラス/インターフェイスにそれらを定義させてください!!!

それまでの間、唯一のオプションはString getUserFriendlyName();、インターフェースまたは抽象クラスでメソッドを定義することです。それほどエレガントではなく、おそらくそれほど効率的ではありませんが、現在、他の選択肢はありません。

于 2015-07-24T22:07:02.927 に答える