Question

I wonder why the following generic definition does not produce a compiler warning:

class MyClass<T extends List> { }

and how the above definition is different to

class MyClass<T extends List<?>> { }

Whenever you read about generics, you read about how raw types should be avoided and consequently, whenever you handle generic types, you get a compiler warning. The raw type inside of the first definition does however not create such a warning.

Secondly, I wonder how the exact subtyping definition between raw types and generic types are. According to this summary, raw types are kind of an "opt-out" of type checking such that type checking is simply inactive whenever a raw type is involved. Is this assumption correct? And how does this effect the above "raw" generic definitions?

Thank you for your help!

UPDATE: I understand what you are saying. However, this is not what I am confused about. Look at this scenario:

class MyClass<T extends MyClass<T>> {}

public void callWildcard1(MyClass<?> node) {
    callBound1(node);
}

public <T extends MyClass<T>> void callBound1(T node) {
    // Do something
}

public void callWildcard2(MyClass<?> node) {
    callBound2(node);
}

public <T extends MyClass> void callBound2(T node) {
    // Do something
}

The first call from callWildcard1 to callBound1 is not allowed because of the generic constraint. The second is however allowed. How can I perform the first call without "inner raw types"? I don't see why the compiler would forbid the first. Shouln't any parameter valid wildcard parameter imply ? extends MyClass<?>?

UPDATE 2: I found out by trial and error, that I can solve the problem by defining:

public <T extends MyClass<? extends T> void callBound2(T node) {
    // Do something
}

even though I do not quite understand why. But there is even more confusion, when looking at this example: (this is a very simple version of what I am actually trying to do.)

public void call() {
    genericCall1(new MyFilter<MyClass<?>>(), MyClass.class);
    genericCall2(new MyFilter<MyClass<?>>(), MyClass.class);
}

public <T extends MyClass<? extends T>> void genericCall1(MyFilter<T> filter, Class<? extends T> filterBoundary) {
  // Do something.
}

public <T extends MyClass<? extends T>, U extends T> void genericCall2(MyFilter<T> filter, Class<? extends U> filterBoundary) {
  // Do something.
}

class MyClass<T extends MyClass<T>> { }

class MyFilter<T extends MyClass<? extends T>> { }

Why is genericCall1 prohibited and genericCall2 is not? Again, I found the solution by an academic guess instead of true understanding. Sometimes, when working with Java and its generics I want to cry...

Was it helpful?

Solution

The difference is that when you use class MyClass<T extends List> { } inside MyClass you lose type safety.

for example:

class A <T extends List<?>>{
    void someFunc(T t) {
        t.add(new Object());//compilation error
    }

}

class B <T extends List>{
    void someFunc(T t) {
        //compiles fine
        t.add(new Object());
        t.add("string");
        t.add(new Integer(3));
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top