2

Why does the compiler request an explicit cast here?

public class Predicate<T> {

    private String operand1; 
    private String operator; 
    private T operand2; 
    private Class<T> classType; 

    public Predicate(String operand1, T operand2){
        this(operand1, "=", operand2); 
    }

    @SuppressWarnings("unchecked")
    public Predicate(String operand1, String operator, T operand2){
        this.operand1 = operand1; 
        this.operator = operator; 
        this.operand2 = operand2; 
        this.classType = (Class<T>) operand2.getClass(); 
    }
}

If the class uses a generic T, and requests a generic T typed argument to be set as T typed field, then why does the compiler doubt about the correctness of the type?
If the cast is made, then why does the compiler still throw a warning about the cast being potentially unsafe?
Additionally, should I be worried about the warning?

In case you wonder why I need it, I use this class type to define stmt.set in preparedStatement (jdbc) later on.

html_programmer
  • 18,126
  • 18
  • 85
  • 158
  • 2
    Related: http://stackoverflow.com/q/18782882/139010 and http://stackoverflow.com/q/18198322/139010 – Matt Ball Jan 24 '16 at 19:50
  • 2
    Even if we ignore that getClass() return Class>, if you have a Predicate, you can pass an Integer as argument, and the class of an Integer is Class, not Class. – JB Nizet Jan 24 '16 at 19:52
  • @JBNizet I thought that generics didn't support inheritance, which wouldn't allow to pass an Integer to Class (for which I would use a bound wildcard). (Unless I'm misinterpreting here). – html_programmer Jan 24 '16 at 19:56
  • Ok for the getClass() returns Class>. If that's the case, it should be safe, since the constructor only accepts a parameter of type T. – html_programmer Jan 24 '16 at 20:02
  • @KimGysen You can't pass a Class if the method expects a Class, but you can pass an Integer if the method expects a Number, because an Integer **is a** Number. Your method takes a T as argument, not a Class. – JB Nizet Jan 24 '16 at 20:08
  • @KimGysen: An `Integer` *is* a `Number`. Generics don't change that. The statement that "generics don't support inheritance" is a distortion of the fact that, for example, a `List` is *not* a `List`. So if `getClass()` behaved as one might naively expect, it would have return-type `Class extends T>`, not `Class`. (But in fact it has return-type `Class extends |T|>`, meaning `Class>`, anyway.) – ruakh Jan 24 '16 at 20:09
  • @KimGysen: So your cast is *not* safe, because it assumes that `getClass()` returns `T.class`, when in fact it may return some subclass. – ruakh Jan 24 '16 at 20:10
  • @ruakh Aha I see the problem. I seem unable to lower limit the T parameter on the constructor. Is it possible, or should I change strategy? My initial way was to explicitly send the class type per invocation, but that didn't seem very clean from the other perspective. I can ask another question if needed, since I can't seem to find a satisfactory solution. (+thanks @JBNizet) – html_programmer Jan 24 '16 at 20:25

0 Answers0