Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

generics question

I get a warning about unchecked casts on the "return (T) value;" line. Is there a better way to do this, or should I just suppress the warning?

class SomeClass<T>
{
    /* ... other methods ... */

    private Set<T> aSet;
    public T filter(Object value)
    {
        if (this.aSet.contains(value))
            return (T) value;
        else
            return null;
    }
}

edit: I'm stuck with public T filter(Object value) as a signature.

like image 776
Jason S Avatar asked Dec 09 '22 14:12

Jason S


2 Answers

What about using the generic type argument as the argument type to filter.

class SomeClass
{
    /* ... other methods ... */

    private Set<T> aSet;
    public T filter(T value)
    {
        if (this.aSet.contains(value))
            return (T) value;
        else
            return null;
    }
}

Ok, since you're stuck with the object signature, you don't have any other chance but do disable/ignore the warning. Java Generics are no "real generics" in the sense that the underlying type system supports them. In fact, they're just a compiler thing since they're based on Type Erasure. Performance penalities and possibly unsafe casting is the price for maintaing binary compatibility with older versions of the JVM.

You can contrast that with the .NET CLR that has real generics, I've written a blog post comparing the two approaches recently to which you can also refer if any of what I said above left you confused.

like image 73
Johannes Rudolph Avatar answered Dec 12 '22 05:12

Johannes Rudolph


In this case you could suppress the warning and leave a comment why it is save:

   if (this.aSet.contains(value)) {
        // this following cast from Object to T is save, because ...
        @SuppressWarnings("unchecked") T result = (T) value;
        return result;
   } else
        return null;

There's an alternative but that would require, that the class or the method 'knows' it's parametized type. Then we can cast without a warning (but should comment too). I show a solution where we introduce / change a constructor to store the 'generics' information as a field:

public class SomeClass<T> {

    private Set<T> aSet;

    private Class<T> genericType;
    public SomeClass(Class<T> genericType) {
        this.genericType = genericType;
    }

    public T filter(Object value)
    {
        if (this.aSet.contains(value))
            // this following cast from Object to T is save, because ...
            return genericType.cast(value);
        else
            return null;
    }
}
like image 42
Andreas Dolk Avatar answered Dec 12 '22 04:12

Andreas Dolk