我想知道是否可以添加类似 Objects.equals() 之类的东西来允许编译时检查类型。
注意:我知道,这不是您一直想做的事情,但我认为它有它的用例。至少对我来说。
示例问题:我有一些类,比如说,一个 Integer 类型的 id。我有一个实体 Foo ,其中
foo.getId()
返回 Integer 类型。由于某些原因,我检查是否与 Objects.equals(someId, foo.getId())
相等。foo.getId()
将不再返回 Integer,而是返回 Long。不幸的是,根本不会有编译时提示 Objects.equals(someId, foo.getId())
永远不会返回 true。 (是的,像 sonarqube 这样的东西对你有一点帮助)。
为了解决这个问题,我想我写了类似的东西
private static <T> boolean equals(T object1, T object2) {
return Objects.equals(object1, object2);
}
这......只是行不通。它仍然接受任何任意对象。 Java 有没有可能解决这个问题?
编辑:请注意,这个问题与对象的 equals 和 hashCode 或一般对象的覆盖 equals 无关,我正在寻找编译时解决方案。
我认为除了编写一堆
equals()
方法之外,没有快速的解决方案。如果您只想使用一组有限的类型,这可能是可行的:
public class Equals {
public static boolean equals(Integer a, Integer b) {
return Objects.equals(a, b);
}
public static boolean equals(Long a, Long b) {
return Objects.equals(a, b);
}
public static void main(String[] args) {
// System.out.println(equals(1, 1L)); doesn't compile
System.out.println(equals(1, 1));
System.out.println(equals(1L, 1L));
}
}
正如托马斯已经提到的,我也想不出快速的解决方案。
您有多种选择,其中一些您可能已经尝试过:
equals
您可以使用自己的
equals
方法,强制您传递两个相同类型的参数(要么都是 Integer
要么都是 Long
)。这就是Thomas提出的解决方案。
您可以通过类型转换强制某种类型:
Objects.equals((Integer) someId, (Integer) foo.getId())
如果您更改任一参数的类型,编译器就会开始抱怨。
应用封装。创建一个类
Id
,在其中存储实际值,可以是 Long
或 Integer
。然后,如果您在任何地方返回 id,请使用 Id
类。直接使用 Long
或 Integer
的问题是暴露了内部实现。当你改变实现时,你就改变了接口。现在不幸的是,仅封装并不能解决问题,因为<T> boolean equals(T a, T b)
仍然会导致T
被推断为Object
。
但是你可以让这个
Id
类泛型,并且由于泛型是不变这一事实,如果你抛出不同的类型,编译器将会抱怨。这是一个例子:
record Id<T>(T value) { }
public static <T> boolean equals(Id<T> a, Id<T> b) {
return Objects.equals(a.value(), b.value());
}
现在让我们定义一些简单的
Foo
:
class Foo {
Id<Integer> getId() {
// Return some dummy value for demonstration purposes
return new Id(23);
}
}
现在让我们用以下代码来测试一下:
Foo foo = new Foo("23");
Id<Integer> someOtherInteger = new Id<>(23);
compare(foo.getId(), someOtherInteger);
下面的代码可以编译,但现在尝试更改
Foo#getId()
以返回 Id<Long>
– 编译器开始抱怨。
Long
您也可以切换到
Long
,并希望您不需要大于 9,223,372,036,854,775,807 的 id。