我想问一问,在Java 8+中是否可以声明泛型绑定T
,以便它扩展超类/超接口U
(可以是Object
或{ {1}}),但如果Serializable
扩展了T
(必须先扩展L
),则会中断编译。
我使用过滤器范围对象发现了这个问题:我的一位开发人员调用了错误的方法,并花了很多时间质疑为什么它给出的结果不一致。因此,我想以某种方式帮助她更改方法签名,以及早发现她使用了错误的代码。
我将以非常简化的方式显示示例案例。我们正在谈论表和动态过滤器。
U
现在的问题是我的泛型的上限#Displays a text "[field name] is equal to [value]"
#Value (T) must be Oject
#Internally uses Object::toString
#Null shows blank string
public static String <T> localizeEq(Localizable fieldName, T value);
<LocalDate> localize(forI18nLabel("DATE_OF_BIRTH_LABEL",dateOfBirth)
"Date of birth equals 01/01/1900" (en)
"syntymäaika on 01/01/1990" (fi)
#Additional diplays for "ge, gte, le..."
#Overload methods not displayed
#SimpleFilter is {op:"ge|ge|eq...",value:""}}
#The effective display depends on the op attribute
#Example "[field name] is [operator] [value]"
#Example "[field name] is less or equal than [upper]"
#If <filter != null but filter.op == null || filter.value> the method returns null
public static String <T> localize(Localizable fieldName, SimpleFilter<T> filter)
#localize(forI18nLabel("SALARY"),salaryFilter)
#salaryFilter = {op:"lt",value:10000}
#Salary is less than 10000 (en)
是U
,开发人员无意中调用了Serializable
,它接受原子值,其参数类型为{{1} }扩展了localizeEq
。方法SimpleFilter<?>
构建过滤器文本“ [[字段名称]等于{op:null,value:null}”。
主要问题是空检查。操作原子值的方法(例如localizeEq,localizeNe)检查参数是否为null。在继续使用复杂过滤器的方法之前,请先检查filter参数是否为或为空。
这就是问题的原因。显然,我可以 (将修改我的代码以便)在调用该方法时检查Serializable
参数的类型,但有三个缺点:
localizeEq
不为空时,开发人员才能发现问题[编辑] 对于我的特定情况,还有另一个技巧,但是它涉及创建十几个重载的不赞成使用的方法:
value
[编辑3]
代码位于Gist上。请注意,在存储库代码中,我们静态导入value
或@Deprecated
public static String localize[Eq|Ne...](Localizable fieldName, SimpleFilter<?> value){ throw new UnsupportedOperationException("Wrong method");}
方法。在该问题中,假设SimpleFilter.filter
与其他方法属于同一类。并且请注意,我们的存储库中还有其他一些* RangeFilter类可支持Joda Time,Java Util Date和NumericRange。他们都遇到同样的问题。
无论如何,我还是要关注这个问题的范围:禁止通用扩展,这在JLS中似乎是不可能的。
答案 0 :(得分:0)
我想问一下在Java 8+中是否可以声明一个泛型 绑定
T
,以便扩展超类/超级接口U
(可能是Object
或Serializable
),但如果T
扩展L
( 必须首先扩展U
。
您的伪代码中的T
似乎是类型参数,而不是绑定参数。界线有所不同,实际上,对T
设置界线似乎是您要问的问题。确实,没有一个限制,尤其是没有一个 lower 限制,您的localizeEq()
方法不会从泛型中获得任何好处。就目前而言,如果您完全摆脱了T
,并且将第二个参数声明为Object
类型(相当于当前代码)或{{1 }}或其他任何内容。
我认为该方法是通用的,希望通过某种方式使用其类型参数来排除某些子类型的参数,但这在Java中是不可能的,因为
现在的问题是我的泛型的上限U为
Serializable
和开发人员无意中调用了Serializable
, 接受原子类型为localizeEq
的参数的原子值 扩展SimpleFilter<?>
。方法Serializable
建立过滤文字 “ [字段名称]等于{op:null,value:null}”。
如果不应该将localizeEq
传递给SimpleFilter
方法,那么我想说您这里有一个设计缺陷。当然,您可以在 run 时发现违规情况,但是类型系统无法提供表达所需的编译时约束的方法。
对于我的具体情况,还有另一个技巧,但是它涉及创建十几个重载的不推荐使用的方法:
实际上,重载可能是最好的可用解决方案,但我建议您从另一个方向进行处理。而不是为localizedEq()
,localizeEq
,等添加重载,而弃用这些方法的现有版本,而是以localizeNe
重载为非localize
的参数提供所需行为的一个或多个版本。