Javaのジェネリックは、Type消去、ワイルドカードと機能<?...>互換性のない型を作ります

ollie314:

そのことについて申し訳ありませんもう一つの新人の質問、。

以下のコードを考えてみましょう:

public class ExceptionHandler {

   // simple internal manager
   @FunctionalInterface
   private interface ExceptionManager<D extends Exception> {
     int getErrorCode(D e, WebRequest request, 
                      HttpServletRequest servletRequest);
   }

   // One field, just for the illustration 
   // (TypeMismatchException came from spring framework)
   private ExceptionManager<TypeMismatchException> tmeManager = 
      (ex, req, servletRequest) -> {
         int errorCode = 0;
         // ...
         return errorCode;
      };

   // A simple "factory" for an ExceptionManager
   private Function<? extends Exception, 
          Optional<ExceptionManager<? extends Exception>>> factory = (ex) -> {
      if(ex instanceof TypeMismatchException) {
         return Optional.of(tmeManager);
      }
      /* ... */
      return Optional.empty();
   };

   // global  exception manager
   private ExceptionManager<? extends Exception> defaultExceptionManager =
      (exception, request, servletRequest) -> {

         final Optional<ExceptionManager<? extends Exception>> manager = 
                         factory.apply(exception);

         if(manager.isPresent()) {
            return manager.get()
                    .getErrorCode(exception, request, servletRequest);
         }
         return 1;
      };
}

次のコードはコンパイルできません。これは、実際にタイプの非互換性の問題に関する苦情です。

Error:(...) java: incompatible types: java.lang.Exception
      cannot be converted to capture#1 of ? extends java.lang.Exception
Error:(...) java: incompatible types: java.lang.Exception
      cannot be converted to capture#2 of ? extends java.lang.Exception

思考や問題について読んだ後、それは、(jvmの後方互換性のため)型消去ので、コードを実行するJavaようです:

private ExceptionManager<? extends Exception> defaultExceptionManager = 
                   (exception, request, servletRequest) -> { /* ... */ }

なりました

private ExceptionManager<Exception> defaultExceptionManager = 
                   (exception, request, servletRequest) -> { /* ... */ }

これは、実際の最初のパラメータ修正されたgetErrorCode(すなわちexceptionへの)Exception

私は(確認について本当に実際には理解していない)を理解するように、プロセスは、一般的なタイプで同じである必要があります。こうして

private interface ExceptionManager<D extends Exception> { /* ... */ }

なったはずです

private interface ExceptionManager<Exception> { /* ... */ }

その結果、パラメータを修正するegetErrorCodeする方法Exception(私が正しい場合)タイプの非互換性のproblemeは、後もう少し明らかになりました。しかし、私はまだ疑わし程度だcapture#xx of ? extends Exceptionタイプ消去がコードの全体の一部のために有効ではないことを(まだ私の理解力に応じて)この意味するから。

コードのエラーの缶誰かのポイント私を(と私はいくつかのジェネリック医薬品のためのコンパイラの内部動作についての説明、ワイルドカードと型消去を見つけることができるドキュメントかもしれませんか)?

注意:コードは、互換性のない型について不平を言います。

protected ResponseEntity<Object> handleTypeMismatch(final TypeMismatchException ex,
   final HttpHeaders headers, final HttpStatus status,
   final WebRequest request) {
   /* ... */
   int errorCode = defaultExceptionManager.getErrorCode(ex, request, servletRequest);
}

この呼び出しの結果は、

Error:(154, 63) java: incompatible types:
      org.springframework.beans.TypeMismatchException
      cannot be converted to capture#3 of ? extends java.lang.Exception

申し訳ありませんが、この質問と読み、それに答えるために感謝の長さのために!よろしく

ホルガー:

あなたのような関数を宣言するときFunction<? extends Exception, …>、あなたはパラメータの種類が不明であることを言っているし、その結果、あなたがすることはできませんapplyあなたと、この関数は実引数が未知のパラメータの型に互換性があるかどうかわかりません。同じことが適用されるにExceptionManager<? extends Exception>引数として、未知の例外の型を受信します、。

これは、ときに関数が戻ると、戻り値の型を知らないとは異なり? extends R、あなたはまだ結果がに割り当てていることを知っているRかのスーパータイプR

それはジェネリックだった場合、このコードが使用可能になるだろう、着信引数と結果の型の間の関係があり、しかし、あなたが(参照保持する変数を作成することはできませんFunctionジェネリックを)。あなたは型パラメータを宣言することができ、通常の方法を用いてこの問題を解決することができます。とにかくここの機能を乱用しているので、これは、ほとんどストレートフォワードです。

public class ExceptionHandler {
    // simple internal manager
    @FunctionalInterface
    private interface ExceptionManager<D extends Exception> {
        int getErrorCode(D e, WebRequest request, HttpServletRequest servletRequest);
    }
    // One field, just for the illustration 
    private static ExceptionManager<TypeMismatchException> tmeManager = 
       (ex, req, servletRequest) -> {
          int errorCode = 0;
          // ...
          return errorCode;
       };

    // A simple "factory" for an ExceptionManager
    private static <E extends Exception> Optional<ExceptionManager<E>> factory(E ex) {
        if(ex instanceof TypeMismatchException) {
            // unavoidable unchecked operation
            @SuppressWarnings("unchecked") ExceptionManager<E> em
                                         = (ExceptionManager<E>)tmeManager;
            return Optional.of(em);
        }
        /* ... */
        return Optional.empty();
    }
    // global  exception manager
    private ExceptionManager<Exception> defaultExceptionManager
                                      = ExceptionHandler::handleDefault;

    static <E extends Exception> int handleDefault(E exception, WebRequest request, 
                                                   HttpServletRequest servletRequest) {
        final Optional<ExceptionManager<E>> manager = factory(exception);
        return manager.map(em -> em.getErrorCode(exception, request, servletRequest))
                      .orElse(1);
    }
}

特定のハンドラを返すことによって適切であることが分かったときに未チェックの動作が避けられない一つの場所は、ありますinstanceofチェック。例外はサブタイプである可能性があるので注意が、ここで注意する必要がありますTypeMismatchExceptionこれは、インスタンスであることも可能ですTypeMismatchException実行時に、しかし、呼び出し側はそれのためのスーパータイプを置換していますE汎用的な署名がより広範な種類のそれは実際にできるよりを処理できるように約束と同じように、後者は、より危険なシナリオです。限りの方法があるとしてprivate、それは動作しますので、チェックのために使用されるように、簡単に、発信者(複数可)のみ同じインスタンスを渡すことができるの概要ということ。

おすすめ

転載: http://43.154.161.224:23101/article/api/json?id=209978&siteId=1