2

In Java 6 something like MyClass and MyClass<?> were considered equal but in Java 7 they are not.

With Java 7, as an example I stumble to problems with for example Hamcrest matchers that are given an instance of MyClass and a matcher that expects to match MyClass<?>, and they get compilation error saying

no suitable method found for assertThat(MyClass,Matcher<MyClass<?>>)
[ERROR] method Assert.<T#1>assertThat(T#1,Matcher<? super T#1>) is not applicable
[ERROR] (actual argument Matcher<MyClass<?>> cannot be converted to Matcher<? super MyClass> by method invocation conversion)

Why the change? What's the difference here between a rawtype and a generics type that has unspecified type argument?

Suggested answer does not really explain what I wonder here. One of the comments says "use of unbound wildcard (e.g. in a method signature) signals a promise that the method in question is aware of generics and will honor the generic type of that object." Here, again, I feel if it's just a "signal" it should not cause problems at compilation time.

I feel that MyClass<?> is just MyClass with information on what it contains or operates on, but while it's <?>, there's no added information and so they should be considered equal?

vertti
  • 7,539
  • 4
  • 51
  • 81
  • 4
    No, they weren't considered equal in Java 6 either. `MyClass` is a raw type, and `MyClass>` isn't. There's a big difference. Now I dare say the exact handling may have changed, but the claim that they were the same in Java 6 is incorrect. – Jon Skeet May 16 '13 at 05:55
  • possible duplicate of [Difference between an unbound wildcard and a raw type](http://stackoverflow.com/questions/14242174/difference-between-an-unbound-wildcard-and-a-raw-type). See also: [What is a raw type and why shouldn't we use it?](http://stackoverflow.com/questions/2770321/what-is-a-raw-type-and-why-shouldnt-we-use-it). – Paul Bellora May 16 '13 at 05:56
  • The code described above compiles with Java 6 and not with 7. But I'm mainly curious about the specifics of what you claim to be a big difference. I currently think there is no real difference except that it makes some code more cumbersome to write. – vertti May 16 '13 at 06:00
  • @PaulBellora The first one at least does not seem to answer my question. – vertti May 16 '13 at 06:04
  • @vertti They're very different. For instance, this compiles but fails at runtime: `List raw = new List(); raw.add("foo"); Integer i = (Integer) raw.get(0);` but this will fail at compile time when you try to add an item: `List> generic = new List(); generic.add("foo");`. – yshavit May 16 '13 at 06:10
  • Your error message seems to indicate that the argument should be a `Matcher super MyClass>`, which is very different from a `Matcher>`. I don't see why Java 6 would allow it any more than Java 7. Perhaps the library itself changed? – dlev May 16 '13 at 06:10
  • @dlev it's the same test on the same maven build but run on either Oracle's Java 6 or 7. – vertti May 16 '13 at 06:12
  • @vertti , its for type safety , explained it right , at runtime it will give exception so to prevent this , compile time method is evolved – anshulkatta May 16 '13 at 06:17

3 Answers3

3

This seems to be related to a compiler bug that was fixed in Java 7.

The compiler error that you now receive is correct. It looks like you're calling the method with wildcarded generic types, e.g. MyClass<?> and Matcher<MyClass<?>>. Note that a wildcard type argument means "some unknown type", so those arguments could really be MyClass<String> and Matcher<MyClass<Integer>>, which is obviously incorrect.

Using a raw type, e.g. plain MyClass opts out of generic type checking, which is why a call with raw types will compile (but likely fail at runtime with a ClassCastException).

Paul Bellora
  • 54,340
  • 18
  • 130
  • 181
1

EDIT

MyClass and MyClass<?> in Java 6 are not same ,

see this link

For backward compatibility, assigning a parameterized type to its raw type is allowed:

MyClass<String> stringBox = new MyClass<>();
MyClass rawBox = stringBox;               // OK

But if you assign a raw type to a parameterized type, you get a warning:

  MyClass rawBox = new MyClass();

  // rawBox is a raw type of MyClass<T>


  MyClass<Integer> intBox = rawBox;    

// warning: unchecked> conversion

MyClass is not a Generic Type , MyClass<?> is a generic type class which means , MyClass is a containing a type of another class ,

for eg , it is common in Java , we do like this

List<String> listofString = new ArrayList<String>();

here it means variable listofString is a object of List will restrict it contents to only String type of objects. <String> tells generic .

yshavit
  • 42,327
  • 7
  • 87
  • 124
anshulkatta
  • 2,044
  • 22
  • 30
  • Formatting tip: Use backticks (\`) for inline code, especially if it contains generic types. Otherwise, the < and > will look like illegal HTML tags to SO, and it'll just strip them out. `List foo` will look like just "List foo". – yshavit May 16 '13 at 06:12
1

As Jon Skeet said, they were not considered equal, that would be incorrect in my opinion. I cannot see any difference if I try in Java 6 and Java 7 - how do you tried this?

To understand the difference between a raw- and generics-type just have a look at this posting (scroll down to "How's a raw type different from using as a type parameter?"): What is a raw type and why shouldn't we use it?

Community
  • 1
  • 1
anm
  • 545
  • 3
  • 17
  • I feel that the link you gave has an answer that kind of describes what I'm after here: "A raw type is define to be either: The name of a generic type declaration used without any accompanying actual type parameters." – vertti May 16 '13 at 06:10