0

I have a generic class:

public class ResultCard<T extends Bike>

private T bike;

public ResultCard(T bike)
{
    this.bike = bike;
}

public int someMethod()
{
     bike.showSpeed();
}

Then I have several classes which extend Bike. When I tested out the ResultCard bean I was very surprised that I can instantiate it without specifying the type:

ResultCard resultCard = new ResultCard(bikeType);

and the following call worked:

resultCard.someMethod();

I figured that ResultCard would be instantiated with the Object type as its generic since I didn't specify it when instantiating and then the call to someMethod() would throw a compile time error? But that didn't happen. As if it determines the type from my constructor or something?

Is there anything wrong with not specifying the generic type when instantiating my bean? Am I misunderstanding something?

Thank you.

theyuv
  • 1,556
  • 4
  • 26
  • 55
  • 1
    Since T extends Bike, the type of the constructor argument and of the field, in the byte-code, is `Bike`, and not `Object`. Read http://stackoverflow.com/questions/2770321/what-is-a-raw-type-and-why-shouldnt-we-use-it – JB Nizet Jul 05 '15 at 10:06

3 Answers3

0

When you have a generic type parameter with a type bound, as in ResultCard<T extends Bike>, the type parameter is replaced by the bound during compilation. It doesn't matter if you create an instance of a raw type new ResultCard(...) or a parameterized type new ResultCard<SomeBike>(...). After compilation the result will be the same.

Only if you remove the type bound, the type parameter will be replaced by Object as you expected.

Eran
  • 387,369
  • 54
  • 702
  • 768
  • I see. The disadvantage is that now ResultCard holds Bike Objects instead of whichever subclass of Bike I set as the Bike. – theyuv Jul 05 '15 at 10:18
0

What you see is a so-called raw type. Its behaviour is close to ResultCard<Bike>, but there are some gotchas you need to know about (see pg. 36). For example, if you used generics in any overloaded method in this class, e.g. int addNotes(Collection<Object> notes) and void addNotes(List<Note> notes), these two will turn into int addNotes(Collection notes) and void addNotes(List notes), which is likely to change the way the resolution works.

Additionally, as raw types lack the additional type information, the code depending on generic tricks will fail to compile. For example, class Class<T> is a generic class parametrised with the class it represents. As a result, you can define methods that take an instance of Class<T> as a parameter and return T, knowing that it is that same class you've passed. If though you save it to a variable of type Class (no type parameter), the convenient code will fail to compile in a bit obscure way.

alf
  • 8,377
  • 24
  • 45
0

As you have not specified the generic type when instantiating,It is raw type.

To create a parameterized type of ResultCard

ResultCard<Bike> resultCard= new ResultCard<Bike>();

If the actual type argument is omitted, you create a raw type

ResultCard rawResultCard = ResultCard();

Hence ResultCard is the raw type of the generic type ResultCard You can always use the rawtype for your generic type.

Did you know!!!! We did not have List class as generic.But after some time it was given support for generic List.so for backward compatibility still one can use List yet.

Here as you have specifed paramitrized type, It allows to instantiate it with the Bike Class parameter and also allows to call the method.

But instead if it would have been some other class which does not extend the Bike class, then it will give compile time error.

027
  • 1,553
  • 13
  • 23