1

フロー内のさまざまな例外を処理する例外ハンドラークラスを作成しようとしています。ビジネスフローは多くの例外をスローし、ハンドラーにはこれらすべての例外を引数として受け取り、必要な処理を行うメソッドがあります。私が理解できない動作は、ビジネスフローで(特定の例外ではなく)例外のみをキャッチし、このキャッチされた例外インスタンスをハンドラーに渡すと、handle(Exception)のみが呼び出され、特定のハンドラーは呼び出されないことです。特定の例外を対象としたメソッド。次のコードスニペットは私の混乱を説明します。

public class Scrap {

    public static void main(String[] args) {
        try {
            new Handler().handle(new BException());
            throw new BException();
        } catch (Exception e) {
            new Handler().handle(e);
        }
    }

    static class Handler {
        public void handle(AException e) {
            System.out.println(e.getClass());
            System.out.println("AAE");
        }
        public void handle(BException e) {
            System.out.println(e.getClass());
            System.out.println("BBE");
        }
        public void handle(Exception e) {
            System.out.println(e.getClass());
            System.out.println("E");
        }
    }

    static class AException extends Exception {
        private static final long serialVersionUID = 1L;
    }
    static class BException extends Exception {
        private static final long serialVersionUID = 1L;
    }
}

出力は次のとおりです。

class Scrap$BException
BBE
class Scrap$BException
E

別のcatchブロックを次のように追加した場合:

try {
    new Handler().handle(new BException());
    throw new BException();
} catch (BException e) {
    new Handler().handle(e);
} catch (Exception e) {
    new Handler().handle(e);
}

その場合、出力は次のようになります。

class Scrap$BException
BBE
class Scrap$BException
BBE

最初のケースでは、特定の例外を除いて、Handler.handleの呼び出しが特定のメソッドに送信されないのはなぜですか。

注意すべきもう1つのことは、最初のコードにキャストを追加すると、

try {
    new Handler().handle(new BException());
    throw new BException();
} catch (Exception e) {
    new Handler().handle((BException)e);
}

出力は期待どおりです(2番目のスニペットと同じ)

この動作は意図されたものであると確信しています。文書化された動作へのポインタが必要です。また、私が抱えている問題は、ビジネスフローが最大30の例外をスローし、この動作のために30の個別のcatchブロックを作成する必要があることです。

4

4 に答える 4

3

これは、Javaでの静的バインディングと動的バインディングについてです。動的ディスパッチ(ポリモーフィズム)を活用できる唯一の位置は、メソッド呼び出しのドットの前です。括弧内に入る引数は動的ディスパッチの対象ではなく、コンパイラは引数リストで宣言された(静的)タイプの式に基づいて、実行時に変更できない明確なメソッドシグネチャを選択します。

これは、Javaの言語の種類を定義する基本的な機能です。他のほとんどのOOP言語と同様に、単一のディスパッチ言語です。多重ディスパッチOOPは完全に異なるモデルです。たとえば、その場合、メソッドを宣言するクラスのOOPについて誰もが想定している基本的な状況は崩壊します。つまり、メソッドは特定のクラスに属しておらず、別個のエンティティです。特定のケースでは、メソッドhandleはHandlerタイプと同じくらい各Exceptionタイプに属し、Handler内で宣言する意味はあまりありません。

于 2012-10-28T21:04:48.093 に答える
2

最初のケースでは、特定の例外を除いて、Handler.handleの呼び出しが特定のメソッドに送られるのはなぜですか。

最初のケースでは、コンパイル時のタイプがBException次の値で呼び出しています。

new Handler().handle(new BException());

2番目のケースでは、コンパイル時のタイプがException次の値で呼び出しています。

catch (Exception e) {
   new Handler().handle(e);
}

基本的に、オーバーロード(選択されたメソッドシグネチャ)はコンパイル時に発生することに注意する必要があります...実行時に発生するのは、そのシグネチャの実装(メソッド呼び出しのターゲットの継承階層の上下)のみです。 。

于 2012-10-28T21:02:40.663 に答える
1

この動作は、catch-blockでe変数のタイプが。であるためですException。タイプ handle()に基づいて呼び出されるものを変更するには、次のようなことを行う必要があります。Exception

public static void main(String[] args) {
    try {
        new Handler().handle(new BException());
        throw new BException();
    } catch (AException e) {
        new Handler().handle(e);
    } catch (BException e) {
        new Handler().handle(e);
    }
}
于 2012-10-28T21:01:52.723 に答える
1

コンパイラは、変数のコンパイル時の型に基づいてメソッドを選択します。instanceofを使用して、実行時に適切なメソッドを選択できます。

于 2012-10-28T21:03:24.690 に答える