How to implement “equals” method for generics using “instanceof”?

南楼画角 提交于 2019-12-02 19:21:23
Evgeniy Dorofeev

This version gives no warnings

public boolean equals(Object other){
    if (other instanceof SingularNode<?>){
        if ( ((SingularNode<?>)other).value.equals(value) ){
            return true;
        }
    }
    return false;
}

As for casting to SingularNode<T> it does not help anything, you cannot assume that T can be anything but Object.

Learn more about how generics are compiled in Java at

https://docs.oracle.com/javase/tutorial/java/generics/erasure.html

Paul Bellora

Evgeniy's solution and Michal's reasoning are correct - you don't need to worry about the type of T here. The reason is that the equals method doesn't depend on generics to work correctly. Instead, it is declared by Object and it takes an Object. Thus, it's responsible for checking the runtime type of whatever was passed in.

If this happens to be SingularNode<String> and you compare it with a SingularNode<Integer>, then ((SingularNode<?>)other).value.equals(value) is perfectly fine because calling Integer.equals with a String argument will correctly return false.

Michal Borek

I put answer here to put code..

In your example you have (in pseudo code) Integer(5).equals(Char('k')) which is false, according to following equals implementation on java.lang.Integer:

public boolean equals(Object obj) {
    if (obj instanceof Integer) {
        return value == ((Integer)obj).intValue();
    }
    return false;
}

Going that way you don't have to worry about casting.

I have the same problem, however it is more general. I have a class where I do have 3 generic types. I do not need to store any variable of those types because this class is used for transformation. However there are stored 'request' variables and I do use cache based on this class, so I need to implement equals() method that is based on those generics.

Do you know if there is any approach how to do it without reflection? Maybe internal variable of that type.. However it's null then.

public class TheClass<I, O, M> {

    private ClassA param1;
    private ClassB param2;
    private ClassC<M> param3;
    private BiFunction<ClassC<M>, I, Optional<O>> mapping;

    public ClassD<O, M> doSomething(ClassD<I, M> param) {
        ...
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null) {
            return false;
        }
        if (getClass() != o.getClass()) {
            return false;
        }
        TheClass<?, ?, ?> that = (TheClass<?, ?, ?>) o;

        return Objects.equals(getParam1(), that.getParam1()) &&
                Objects.equals(getParam2(), that.getParam2()) &&
                Objects.equals(getParam3(), that.getParam3());
    }
}

For a better imagination... I have set of DAO objects getting data from database. On the other hand, we do have another set of API providers that provide similar data in different format (REST, internal systems..) We need a mapping function from one type to another. We use caching for better performance and the only man-in-the-middle is this class.

You dont need to use any casting. Best equals to implementation I see like this

@Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof VehicleModel)) return false;

        VehicleModel that = (VehicleModel) o;

        if (vehicleName != null ? !vehicleName.equals(that.vehicleName) : that.vehicleName != null)
            return false;

        return true;
    }
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!