tags:

views:

1481

answers:

3

I have the following code that won't compile and although there is a way to make it compile I want to understand why it isn't compiling. Can someone enlighten me as to specifically why I get the error message I will post at the end please?

public class Test {
    public static void main(String args[]) {
     Test t = new Test();
     t.testT(null);
    }

    public <T extends Test> void testT(Class<T> type) {
     Class<T> testType = type == null ? Test.class : type; //Error here
     System.out.println(testType);
    }
}

Type mismatch: cannot convert from Class<capture#1-of ? extends Test> to Class<T>

By casting Test.class to Class<T> this compiles with an Unchecked cast warning and runs perfectly.

+1  A: 

Remove the conditional and the error is a little nicer...

public class Test {
    public static void main(String args[]) {
        Test t = new Test();
        t.testT(null);
    }

    public <T extends Test> void testT(Class<T> type) {
    Class<T> testClass = Test.class;
        System.out.println(testClass);
    }
}


Test.java:10: incompatible types
found   : java.lang.Class<Test>
required: java.lang.Class<T>
        Class<T> testClass = Test.class;
Ken
+11  A: 

The reason is that Test.class is of the type Class<Test>. You cannot assign a reference of type Class<Test> to a variable of type Class<T> as they are not the same thing. This, however, works:

Class<? extends Test> testType = type == null ? Test.class : type;

The wildcard allows both Class<T> and Class<Test> references to be assigned to testType.

laz
Your code is good, but your explanation doesn't make sense. What is the difference between a Class and a Class reference?
Michael Myers
I just fixed it. I should have paid better attention to the preview! Apparently this thing eats angle brackets instead of escaping them. I guess it can't be perfect.
laz
Ah, now I see! But it looks like you have a few more angle brackets missing, no?
Michael Myers
Oh, and +1, now that I understand what you're saying. :)
Michael Myers
I'd like to understand what you mean by reference of type Class and variable of type Class. Are you talking about Java having references and how does it relate?
PintSizedCat
In Java, a variable that is anything other than a primitive type is a reference. I'm using the term variable to refer to the left-hand-side of the assignment and the term reference to refer to the right-hand-side.
laz
+1  A: 

Suppose I extend Test:

public class SubTest extends Test {
  public static void main(String args[]) {
    Test t = new Test();
    t.testT(new SubTest());
  }
}

Now, when I invoked testT, the type parameter <T> is SubTest, which means the variable testType is a Class<SubTest>. Test.class is of type Class<Test>, which is not assignable to a variable of type Class<SubTest>.

Declaring the variable testType as a Class<? extends Test> is the right solution; casting to Class<T> is hiding a real problem.

erickson