Java和equals()方法中的泛型类:类型安全

时间:2019-04-05 10:42:38

标签: java

我想重写泛型类中的equals()方法,并且必须将Object强制转换为我的泛型类型Pair。

我添加了@SuppressWarnings(“ unchecked”)来“静音”警告,但是问题仍然存在。方法getType()和getClass()也不适用于泛型类型,因此使用T.getType()成为不可能。

public class Pair<T, U> {
    private T first;
    private U second;

    public Pair(T _first, U _second)
    {
        first = _first;
        second = _second;
    }

    public boolean equals(Object obj) {
         if (this == obj)
           return true;
         if (obj == null)
           return false;
         if (getClass() != obj.getClass())
           return false;

        //Problem ahead!!!
         Pair<T, U> other = (Pair<T, U>) obj;

                   ...
    }
}

是否有一般的良好做法或“技巧”来正确,安全地执行此操作?

6 个答案:

答案 0 :(得分:5)

您可以将obj投射到Pair<?, ?>上,并在equalsfirst上调用second

Pair<?, ?> other = (Pair<?, ?>) obj;
return other.first.equals(first) && other.first.equals(second);

通过这种方式,T.equalsU.equals的类型检查将由TU处理。

答案 1 :(得分:3)

您可以这样编写equals方法:

@Override
public boolean equals(Object object) {
    boolean equal = false;

    if(this == object){
        equal = true;
    } else if(object instanceof Pair<?, ?>) {
        // Check that object is an instance of Pair<?, ?>, this will also null check.
        // Then just case object to Pair<?, ?> like.
        Pair<?, ?> pair = (Pair<?, ?>) object;

        if(((this.first == null && pair.first == null) || (this.first != null && this.first.equals(pair.first))) &&
                ((this.second == null && pair.second == null) || (this.second != null && this.second.equals(pair.second)))){
            equal = true;
        }
    }
    return equal;

?之间的<>有点像通配符,实际上被归类为无界通配符;这意味着尚未指定类的类型。

object instanceof Pair<?, ?>将检查两件事,首先将检查对象是否不为空,因此为您创建null的安全性,然后它将检查对象的类型为{{1} }。

您可以了解通配符here

根据Pair<?, ?>,如果您要覆盖ntalbs,请不要忘记也覆盖equals

hashCode

为什么覆盖@Override public int hashCode() { final int prime = 31; int result = super.hashcode; result = result * prime + (this.first == null ? 0 : this.first.hashCode()); result = result * prime + (this.second == null ? 0 : this.second.hashCode()); return result; } 时必须覆盖hashCode

  

您必须在每个覆盖equals()的类中重写hashCode()。否则,将违反Object.hashCode()的一般约定,这将阻止您的类与所有基于哈希的集合(包括HashMap,HashSet和Hashtable)一起正常运行。

答案 2 :(得分:2)

您可以使用instanceof检查对象的类型,然后安全地对其进行投射。

if(obj instanceof Pair){
    Pair other = (Pair) obj;
}

答案 3 :(得分:1)

首先要记住,泛型仅在编译时处于活动状态。它们是编译时检查的额外一层,以确保您不会误用可能采用不同类型的容器或函数。

还请记住,equals()自Java的第一个发行版以来就一直存在,而泛型是在Java 1.5中引入的。因此,对于这种特定的方法,您自然会进行某种类型转换。

在投射对象之后,无论如何,您都将检查Pair的每个单独的元素,因此,如果它们的类型不同,它们也将通过相等性检查。

答案 4 :(得分:1)

由于泛型类型在编译时被擦除,因此您无法在运行时检查该类型。因此,您应该将其强制转换为equals

如果使用JDK 7或更高版本,则还可以在Pair<?,?>方法中使用Objects.equals(..)。这将简化代码,因为您不必担心equalsfirstsecond

null

此外,如果您在类中添加了Pair<?, ?> pair = (Pair<?, ?>) obj; return Objects.equals(first, pair.first) && Objects.equals(second, pair.second); 方法,请不要忘记实现hashCode

equals

答案 5 :(得分:-1)

package com.journaldev.generics;

public class GenericsMethods {

//Java Generic Method
public static <T> boolean isEqual(GenericsType<T> g1, GenericsType<T> g2){
    return g1.get().equals(g2.get());
}

public static void main(String args[]){
    GenericsType<String> g1 = new GenericsType<>();
    g1.set("Test");

    GenericsType<String> g2 = new GenericsType<>();
    g2.set("Test");

    boolean isEqual = GenericsMethods.<String>isEqual(g1, g2);
    //above statement can be written simply as
    isEqual = GenericsMethods.isEqual(g1, g2);
    //This feature, known as type inference, allows you to invoke a generic method as an ordinary method, without specifying a type between angle brackets.
    //Compiler will infer the type that is needed
}
}