Java是否有可能禁止泛型中的某些超类?

时间:2019-06-11 13:00:07

标签: java generics

我想问一问,在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不为空时,开发人员才能发现问题
  • 我公司中没有人运行自动测试,因此只有在启动整个应用程序并将过滤器设置为非null值时,他们才会发现。手动测试一旦完成,就永远不会重复

[编辑] 对于我的特定情况,还有另一个技巧,但是它涉及创建十几个重载的不赞成使用的方法:

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中似乎是不可能的。

1 个答案:

答案 0 :(得分:0)

  

我想问一下在Java 8+中是否可以声明一个泛型   绑定T,以便扩展超类/超级接口U(可能是   ObjectSerializable),但如果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的参数提供所需行为的一个或多个版本。