覆盖“等于”方法:如何确定参数的类型?

我正在尝试为参数化类重写equals方法。

 @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (!(obj instanceof Tuple)) return false; Tuple other = (Tuple) obj; //unchecked cast if (!a0.equals(other.a0) && !a0.equals(other.a1)) { return false; } if (!a1.equals(other.a1) && !a1.equals(other.a0)) { return false; } return true; } 

如何确保other对象的与此相同?

您可以通过保留对Class类型的引用来完成此操作。 但是,在我看来, 相等测试应该是对象所代表的值,而不是值表达的具体类型

一个典型的例子就是Collections API。 new ArrayList().equals(new LinkedList())返回true 。 虽然它们具有完全不同的类型,但它们代表相同的值,即“空集合”。

就个人而言,两个表示相同数据的Tuple (例如("a", "b") )是否不相等,因为一个是Tuple类型而另一个是Tuple

因为擦除你不能。 关于你可以做的最好的事情是在元组类中存储你计划用于保存在“java.lang.Class”字段成员中的元组的类型。 然后你可以比较这些字段以确保元组类保持相同的类型。

另请参阅此主题: Java中的C ++ Pair 的等价物是什么?

如果你发布更多关于你的课程,这将有所帮助。 我在考虑未经检查的演员表和你所等的字段数意味着它应该是元组不是吗?

编辑:这是我经常使用的有用的Pair类(如果需要,你可以调整你的Tuple类)。 注意,类似于其他人的建议,这个类只是让包含的成员决定平等的问题。 您的用例应该确定相等性是否真正基于所包含成员的类型。

 /** * Adapted from http://forums.sun.com/thread.jspa?threadID=5132045 * * * @author Tim Harsch * * @param  * @param  */ public class Pair { private final L left; private final R right; public R getRight() { return right; } // end getter public L getLeft() { return left; } // end getter public Pair(final L left, final R right) { this.left = left; this.right = right; } // end constructor public static  Pair create(A left, B right) { return new Pair(left, right); } // end factory method @Override public final boolean equals(Object o) { if (!(o instanceof Pair)) return false; final Pair other = (Pair) o; return equal(getLeft(), other.getLeft()) && equal(getRight(), other.getRight()); } // end method public static final boolean equal(Object o1, Object o2) { if (o1 == null) { return o2 == null; } return o1.equals(o2); } // end method @Override public int hashCode() { int hLeft = getLeft() == null ? 0 : getLeft().hashCode(); int hRight = getRight() == null ? 0 : getRight().hashCode(); return hLeft + (37 * hRight); } // end method @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append('<'); if( left == null ) { sb.append("null"); } else { sb.append(left.toString()); } // end if sb.append(','); if( right == null ) { sb.append("null"); } else { sb.append(right.toString()); } // end if sb.append('>'); return sb.toString(); } // end method } // end class 

我自己也遇到了这个问题,在我的特定情况下,我不需要知道E型。

例如:

 public class Example { E value; public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Example other = (Example) obj; if (value == null) { if (other.value != null) return false; } else if (!value.equals(other.value)) return false; return true; } } 

在上面的代码中,由于使用了Example ,因此没有未经检查的强制转换。 类型参数通配符’?’ 节省了一天。

可悲的是,你不能在编译时这样做; 信息消失了。 这就是类型擦除的后果。 另一种方法是将参数存储为Class实例,然后再查找。

由于generics在编译时被删除 ,你基本上不能。 在运行时,任何类型参数都消失了,就JVM而言,它们在所有方面都完全相同。

解决这个问题的方法是存储一个表示类型的Class字段,并在构造函数中创建具有该类型的对象。

示例构造函数:

 public class Tuple < E > { public Tuple(Class c) { //store the class } } 

或者你可以使用工厂:

 public static  Tuple  getTuple(Class type) { // Create and return the tuple, // just store that type variable in it // for future use in equals. } 

使用Class对象保留对E类型的引用的建议似乎效率低下 (这对于占用内存的Class很多毫无意义的引用)并且对于您的问题毫无意义。

一般情况下, FooFoo应该是不相等的。 所以你不需要E 并且,在您编写的代码中,您甚至不需要它来编译。 简单地演绎到Tuple ,因为那时你真正了解了Tuple 。 它仍然编译和所有。

如果你使用两种截然不同的类型的数据传递Tuple s,那些元素将不是equals ,并且你的方法将根据需要返回false 。 (人们希望 – 取决于那些实现equals类型。)

偏离主题 – 您是否意识到根据您的实现,元组(a0,a1)等于元组(a1,a1)? 我怀疑那不是你想要的……

正如其他人所说的那样,在主题上,擦除使得这是不可能的。 但是你应该重新考虑为什么要这样 – 平等检查只在运行时发生,而generics只是编译时 。 从概念上讲, 变量具有通用参数,但对象则不具有。 因此,当您比较对象的相等性时,通用参数根本不重要; 无论如何,你不能在运行时根据它们采取任何适当的行动。

对象相等和通用参数共同/反向方差是两个正交问题。

我同意上述评论,为什么E级需要平等? 以及如何处理E的子类?

无论如何,鉴于这是一个可能对您有帮助的代码示例:

 public class Example { T t; public Example(T t) { this.t = t; } public static void main(String[] args) { final String s = "string"; final Integer i = 1; final Number n = 1; final Example exampleString = new Example(s); final Example exampleInteger = new Example(i); final Example exampleNumber = new Example(n); System.out.println("exampleString subclass " + exampleString.t.getClass()); System.out.println("exmapleIntger subclass " + exampleInteger.t.getClass()); System.out.println("exmapleNumber subclass " + exampleNumber.t.getClass()); System.out.println("Integer equals Number = " + exampleInteger.t.equals(exampleNumber.t)); } } 

您可以调用t.getClass()来获取有关T类型的类信息(当然,假设它不是null)。

我希望这有帮助。