0

Java での作業。

私はそのような抽象クラスを持っています:

public abstract class Foo {
    protected Logger log = null;

    // other stuff

    public boolean isLoggerSet() {
        return (this.log != null) ? true : false;
    }
}

今、私はこのクラスを次のように拡張します:

public class Bar extends Foo {
    public Bar() {
        this.log = Logger.getLogger(Bar.class);
    }

    public void someMethod(String[] args) {
        Bar b = new Bar();
        if(b.isLoggerSet()) {
            // do some stuff
        }
    }
}

The question:Bar には と呼ばれる独自のローカル変数がないため、super.log呼び出してもBar.class は実際に を参照していますか? または、メソッドを実装する正しい方法は、メソッドを抽象化し、Bar.classが拡張されているため、そのローカル コピーにそれ自体を実装するように強制することでしょうか?this.loglogisLoggerSet()log

基本的にthis.log、Foo クラスで言わなければならないのは、自分自身を参照するからです。しかし、 Bar クラスでは null check を実行できるようにしたいのですがlog、代わりsuper.log =に Bar.class で使用する必要がありますか?

4

5 に答える 5

3

ロガーをstaticではなく に設定しましたprotectedsuperまたはを使用するかどうかにthis関係なく、この場合はまったく同じ変数を指します。

于 2013-05-21T19:13:31.337 に答える
2

クラス階層で呼び出される属性が 1 つしかない場合、またはlogと言っても問題ありません。同じもの、つまり唯一のものを参照します。this.logsuper.log

于 2013-05-21T19:13:03.567 に答える
2

クラスは、オブジェクトを作成するための設計図です。あなたの場合、「Bar」の青写真は「Foo」で定義された青写真に追加されます(これは「Object」で定義された青写真に追加されます)。

基本クラスに混乱させないでください:概念的には、コンパイラはすべての基本クラスを 1 つのトップレベルの結合クラスにプルアップします (「オブジェクト」ベースは無視します)。

public class Bar {

    protected Logger log = null;

    public boolean isLoggerSet() {
        return (log != null) ? true : false;
    }

    public Bar() {
        log = Logger.getLogger(Bar.class);
    }

    public void someMethod(String [] args) {
        Bar b = new Bar();
        if(b.isLoggerSet()) {
            // do some stuff
        }
    }

}

次のようにコードを実行します。

Bar x = new Bar();
x.isLoggerSet(); // Returns true since Bar() constructor just set it
x.someMethod(args);

最初の行は、メモリ内に "Bar" 型の新しいオブジェクトを作成します。このオブジェクトには、「new Bar()」を使用して最初の行の Bar コンストラクターに設定される「Logger」オブジェクトへのポインターが 1 つあります。

次の行は「isLoggerSet」をチェックします。「getLogger」がライブ オブジェクトを返すと仮定すると、「isLoggerSet」は常に true を返します。

最後の行は「x.someMethod(args)」を呼び出します。このメソッドは、新しい「バー」オブジェクトを作成します (そのコンストラクターはその「ログ」ポインターを設定します)。したがって、「b.isLoggerSet()」もここで渡されます。

于 2013-05-21T21:15:04.297 に答える
1

少し変更した例を次に示します。

public abstract class Foo {
    protected String name;

    public Foo() {
        name = "Mr. Foo";
    }
}

public class Bar extends Foo {
    protected String name;

    public Bar() {
        name = "Mr. Bar";
    }

    public void someMethod() {
        System.out.println("this.name=" + this.name);
        System.out.println("super.name=" + super.name);
    }

    public static void main(String[] args) {
        Bar bar = new Bar();
        bar.someMethod();
    }
}

出力:

this.name=Mr. Bar
super.name=Mr. Foo

そのため、各クラスに 1 つずつ、'name' と呼ばれる 2 つの変数があります。サブクラス内からスーパークラスにアクセスするには、「super.name」を使用する必要があります。

Bar() を作成するとき、Java は、コンストラクターの最初の行として、スーパークラスのコンストラクターへの super(...) 呼び出しをチェックします。そこにない場合 (上記のように)、「super();」コンストラクタの最初の行として目に見えないように挿入されます。だから私は書くことができた:

....
    public Bar() {
        super();
        name = "Mr. Bar";
    }
....

同じ結果です。ただし、これは必須ではありません。自分でスーパー コンストラクターを呼び出さない場合、Java はデフォルト コンストラクターへのスーパー コールを挿入します。このようにして、コンストラクターの連鎖が強制されます。

スーパーコンストラクターを自分で呼び出したい場合は、デフォルト以外のコンストラクターを呼び出すこともできます。次に例を示します。

    public abstract class Foo {
        protected String name;

        public Foo() {
            name = "Mr. Foo";
        }

        public Foo(String name) {
            this.name = name;
        }
    }

    public class Bar extends Foo {

        public Bar() {
            super("Mr. Bar");
        }

        public void someMethod() {
            System.out.println("this.name=" + this.name);
            System.out.println("super.name=" + super.name);
        }

        public static void main(String[] args) {
            Bar bar = new Bar();
            bar.someMethod();
        }
    }

出力:

this.name=Mr. Bar // refers to 'name' inherited from Foo
super.name=Mr. Bar // refers to 'name' in superclass, set by the String constructor
// so these both refer to the same variable in this example

この最後の例では、Foo のデフォルトのコンストラクターが呼び出されていないことに注意してください。

于 2013-05-21T20:00:57.987 に答える