我正在尝试为我的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说:
ValidationUtil.DataValidator类型中的方法validate(capture#3-of?)不适用于参数(T)
我无法理解这个消息。如果可能的话,如何修改或修改代码以使其有效?
提前感谢您提出意见和建议。
答案 0 :(得分:3)
您收到该错误是因为您使用的是通用通配符,而且您的代码不是类型安全的。
dataType.validator
是DataValidator<?>
,表示:DataValidator
某种未知类型(由?
表示)。当您使用某种类型validate()
的值调用T
时,编译器会抱怨,因为DataValidator
接受的类型未知。因此,它无法检查类型T
是否属于此DataValidator
应该允许的类型。
一种解决方案是不使用通用通配符。
问题很复杂,因为你在enum
和enums 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.
}
你可以做的是拥有一个带常量的类:
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;
}
}
答案 1 :(得分:1)
枚举中的字段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
声明为这样的常量,那么它们将是类型安全的:
public static class Validators {
public static final DataValidator<String> TAX_CODE_VALIDATOR = ...;
}
用法:
Validators.TAX_CODE_VALIDATOR.validate("12345");