2017-02-02 4 views
0

私はすべての私のカスタム例外ParentExceptionの親クラスを持っています。すべての子例外に、例外にメッセージを追加するメソッドが必要です。これを行うために、ジェネリック型のオブジェクトを返すジェネリックメソッドを作成しました。私はthisを親クラスのメソッドで使用してメッセージを追加してからthisを返しますが、このメソッドはジェネリック型を返すのでジェネリック型Tにキャストしました。これはうまくいくと思われますが、警告が表示されます。次のように私のコードは次のとおりです。Java:ジェネリックが<T extends Parent>の場合、親クラスのジェネリック型にキャストしていますか?

public class ParentException extends RuntimeException{ 

    private String message; 

    public ParentException() { 
     message = ""; 
    } 

    public void addToMessage(String msg) { 
     message += msg; 
    } 

    public void printMessage() { 
     System.out.println(message); 
    } 

    public <T extends ParentException> T withMessage(String msg) { 
     this.addToMessage(msg); 
     return (T) this; // This line gives the warning 
    } 
} 

そのラインで与えられた警告はUnchecked cast from ParentException to Tです。このメソッドは期待どおりに動作するように見えるので、私は心配していませんが、なぜこれが最初に警告を出すのかをよりよく理解したいと思います。

このキャストは常に安全ですか?それ以外の場合は、実行時エラーが発生しますか?

+4

'T'が' ParentException'の子であると推測できるため、安全ではありません。その場合、キャストは失敗します( 'ParentException'オブジェクトで呼び出された場合)。 'T'が実際に' ParentException'である場合にのみ動作します。 –

+0

なぜここでジェネリックを使用する必要があるのか​​分かりません。 –

答えて

1

次のコードはコンパイルされますが、実行時に失敗します:

class ChildException extends ParentException { } 

ParentException p = new ParentException(); 
ChildException c = p.withMessage("Connection failed"); 

私はそれはそれを書くためにあまり意味がありません実現が、ポイントは、安全でないキャストについて警告コンパイラは防ぐことができるということですこの地雷は、最初の場所です。

+0

ありがとうございました。しかし、 'ParentException'クラスをabstractにするとどうなりますか?それはほとんどの場合には機能しますが、これについてはどうなりますか? 'ParentException p =新しいChildException(); ChildException c = p.withMessage( "Connection Failed"); ' –

+2

このケースでは機能しますが、具体的な子クラスと具体的な孫クラスについてはどうでしょうか?そして、想像を絶するほど、私たちは多くの似たようなシナリオを考え出すことができると思います。 – VGR

+0

これはどうやって危険なのか分かります。そのとき、一般的な解決策は何でしょうか?すべての子クラスのメソッドをオーバーライドする必要はありません。 –

1

は、このケースを考えてみましょう:

class SubException extends ParentException {...} 

ParentException ex = new ParentException(); 
SubException sub = ex.withMessage("blah"); 

ParentExceptionSubExceptionにキャストすることはできませんので、最後の行は、クラスのキャスト例外がスローされます。


あなたは、静的なヘルパーメソッドを作成できます

class ParentException extends RuntimeException{ 
    ... 
    protected static <T extends ParentException> T withMessage(T instance, String msg) { 
     instance.addToMessage(msg); 
     return instance; 
    } 

    public ParentException withMessage(String msg) { 
     return withMessage(this, msg); 
    } 
} 

をそして、このメソッドをオーバーライドするために共変戻り値の型を使用します。

class SubException extends ParentException { 
    @Override 
    public SubException withMessage(String msg) { 
     return withMessage(this, msg); 
    } 
} 

その後、あなたはSubException変数を持っている場合、コールをwithMessageにもSubExceptionが返されます。

+0

ありがとうございました。しかし、 'ParentException'クラスをabstractにするとどうなりますか?それはほとんどの場合には機能しますが、これについてはどうなりますか? 'ParentException p =新しいChildException(); ChildException c = p。withMessage( "Connection Failed"); ' –

+0

@GeoffMcLennanこれは、キャストを隠すトリックです。これは、コンパイル時にコンパイラによって挿入されるためです。それはコンパイルされます: 'ParentException p = new ChildException(); ChildException c =(ChildException)p.withMessage( "Connection Failed"); 'もちろん、その状況での通常のキャストと同じくらい安全です。 –

+0

キャストを隠す以外にも、ParentException型のオブジェクトインスタンス化はありません。私は私のコメントで例をテストしただけで、実行時エラーなしで動作します。 ParentExceptionがabstractの場合、初期のケースで発生したエラーを防ぐことができますが、それでも@VGRのコメントのようにエラーが残っています。 –

関連する問題