java class declaration with the generic type disable method returning another generic type

266 views Asked by At

I have this little problem and I want to find out whay is this happening to me: I made class like this:

public class SomeSimpleClass {
   //and I had method who returns generic. it can be instance of whatever, and for sure can be casted to U:
   public <U>U giveMeSomething(String arg) {
      return (U)SomewhereSomething.getValueCastingIsOK(arg);
   }
}

and then I am using it like this:

// give me some number:
Integer number = instanceSomeSimpleClass.giveMeSomething("I want integer value");

OR

String text = instanceSomeSimpleClass.giveMeSomething("I want text now");

and everything is ok. getValueCastingIsOK from SomewhereSomething returns me what I want, and I dont need type cast on the giveMeSomething. Looks like the U is replaced by the type from the associative variable.. and everything is cool..

BUT then I create a new class:

public class SomeOtherClass <T extends Something> {
   //And I have the exactly same method here:
   public <U>U giveMeSomething(String arg) {
      return (U)SomewhereSomething.getValueCastingIsOK(arg);
   }   
}

and now when I want to use it in the same way, the compiler (I am using Java 1.7) is telling me, that I have to use typecast, and start to using the giveMeSomething like this, because U is now the Object, and nothing else...

Integer number = (Integer)instanceSomeSimpleClass.giveMeSomething("I want integer value");

:(

Why in the second case the compiler cant get the U type in the same way, as in the first case. And what I have to do, to be that this way?

Thank for an answers, suggestions.. ;)

2

There are 2 answers

1
rgettman On

The problem is that you're using a raw type of the class SomeOtherClass, but not supplying any type parameters to your declaration:

SomeOtherClass instanceSomeSimpleClass = new SomeOtherClass();

When you do this, the Java compiler will replace ALL generics in the class with the type erasure version, even unrelated generics such as your generic method. The type erasure of the method

public <U>U giveMeSomething(String arg) {

becomes

public Object giveMeSomething(String arg) {

which requires the cast to Integer.

You must either supply a type parameter to SomeOtherClass (useless, unless you've eliminated unnecessary code that uses T to post the class code here):

SomeOtherClass<Something> instanceSomeSimpleClass = new SomeOtherClass<Something>();

Or you can remove the type parameter on the class definition, as you had it originally:

public class SomeSimpleClass {

Either will keep the generic method intact and eliminate the need to cast the return type of giveMeSomething.

1
Bohemian On

You're missing the java syntax for explicit typing:

public <U>U giveMeSomething(String arg) {
    return SomewhereSomething.<U>getValueCastingIsOK(arg);
}

Notice the <U> between the dot and the method name. Notice also that casting is now not required.

That's how you explicitly declare what the type is for a typed method. Without this, java must infer the type, which it can't here, so (unsafe) casting is required.

Another example to illustrate. In this case, java can infer the type is Integer because of the type that the result is being assigned to:

Integer number = instanceSomeSimpleClass.giveMeSomething("I want integer value");

But if you were to use the value without assigning it, you'd need to pass to type:

someIntegerRequired(instanceSomeSimpleClass.<Integer>giveMeSomething("I want integer value"));