2017-04-21 58 views
0

我正在嘗試爲我的Java應用程序開發靜態驗證方法。我使用了驗證器對象,並使用validate(T data)方法和枚舉來存儲它們。跟隨我的代碼片段。嘗試調用方法時遇到仿製藥問題

public enum ValidationType { 
    TAX_CODE(null); // FIXME 

    private final DataValidator<?> validator; 

    private ValidationType(DataValidator<?> validator) { 
     this.validator = validator; 
    } 
} 

public static <T> void validate(T data, ValidationType dataType) { 
    dataType.validator.validate(data); 
} 

private static abstract class DataValidator<T> { 
    public abstract Class<T> getType(); 
    public abstract void validate(T data); 
} 

當編輯,使用Eclipse,我當我調用validate方法(線dataType.validator.validate(data);)得到了一個錯誤。

Eclipse中說:

的方法驗證(?捕獲#3的)在類型ValidationUtil.DataValidator不適用於

我不明白這個messaga參數(T) 。如果可能的話,我如何修改或修改代碼以使其可用?

非常感謝您的意見和建議。

回答

1

enum中的字段validator的類型是DataValidator<?>,它不會匹配DataValidator<T>

但是,你可以解決,通過創造具有正確的簽名現場的存取方法:

 public <T> DataValidator<T> getValidator() { 
      return (DataValidator<T>)validator; 
     } 

你需要在這裏施展,因爲你是假設在T通過型式實際上屬於到使用的枚舉常量。

換句話說,系統將無法阻止你做愚蠢的事情,如:

TAX_CODE.getValidator().validate(new HashMap<>()); 

不會有檢查TAX_CODE必須是一個String,它將在運行 - 失敗時間與ClassCastException

這裏的調整代碼:

public enum ValidationType { 
     TAX_CODE(null); // FIXME 

     private final DataValidator<?> validator; 

     private ValidationType(DataValidator<?> validator) { 
      this.validator = validator; 
     } 

     public <T> DataValidator<T> getValidator() { 
      return (DataValidator<T>)validator; 
     } 
    } 

    public static <T> void validate(T data, ValidationType dataType) { 
     dataType.getValidator().validate(data); 
    } 

    private static abstract class DataValidator<T> { 
     public abstract Class<T> getType(); 
     public abstract void validate(T data); 
    } 

更新

重寫建議:

如果你像這個常量聲明DataValidator S,那麼他們將是類型安全的:

public static class Validators { 
    public static final DataValidator<String> TAX_CODE_VALIDATOR = ...; 
} 

用法:

Validators.TAX_CODE_VALIDATOR.validate("12345"); 
+0

演員不幸使得它使代碼不是類型安全了。 – Jesper

+0

由於枚舉本身不是通用的,這是觸發驗證的起點,所以它無論如何都不可能是安全的。我認爲可以做到,如果你用類替換枚舉。 – john16384

+0

是的,這是Java中枚舉的一個不幸的限制。有一個[允許枚舉具有類型參數的提議](http://openjdk.java.net/jeps/301),所以這可能會在未來的Java版本中發生變化。 – Jesper

3

,因爲使用的是通用的通配符和你的代碼是不是類型安全的您得到這個錯誤。

dataType.validatorDataValidator<?>,這意味着:某種未知類型的DataValidator(由?表示)。當你調用validate()那個值爲T時,編譯器會抱怨,因爲DataValidator接受的類型是未知的。因此,它不能檢查類型T是否應該允許用於此DataValidator的類型。

一個解決方案是不使用通用通配符。

問題很複雜,因爲您在enumenums cannot have type parameters(至少尚未 - 這可能會成爲未來版本的Java中的一項功能)中具有此功能。這一點,例如,是不允許的:

public enum ValidationType<T> { // Not valid Java! (at least not in Java 8) 
    TAX_CODE(null); // FIXME 

    private final DataValidator<T> validator; 

    // etc. 
} 

你可以做的反而是有常數a類:

public final class ValidationType<T> { 
    public static final ValidationType<String> TAX_CODE = new ValidationType<>(...); 
    public static final ValidationType<Integer> SOMETHING = new ValidationType<>(...); 
    public static final ValidationType<Double> ANOTHER = new ValidationType<>(...); 

    private final DataValidator<T> validator; 

    private ValidationType(DataValidator<T> validator) { 
     this.validator = validator; 
    } 

    public DataValidator<T> getValidator() { 
     return validator; 
    } 
} 
+0

感謝您解釋問題。 –