javagenericsgeneric-method

Using 'diamond' notation for methods in java


I'm currently working on a component-based architecture management system in java. My current implementation of the retrieval of a component attached to an object works like this:

// ...

private final HashMap<Class<? extends EntityComponent>, EntityComponent> components;

// ...

public <T extends EntityComponent> T getComponent(Class<T> component)
  {
    // ... some sanity checks
    if (!this.hasComponent(component))
    {
        // ... some exception handling stuff
    }

    return component.cast(this.components.get(component));
  }

// ...

Now, this works fine, but it somewhat bugs me to have to write

object.getComponent(SomeComponent.class)

everytime I need to access a component.

Would it be possible to utilize generics in a way to shift the syntax to something more along the lines of

object.getComponent<SomeComponent>()

, utilizing the diamond operator to specify the class, instead of passing the class of the component as a parameter to the method?

I know it's not really a big thing, but making the syntax of often used code as pretty / compact as possible goes a long way I guess.


Solution

  • Unfortunately not, since type-parameters are "erased" in Java. That means that they are only available at compile-time (where the compiler is using them to type-check the code), but not at run-time.

    So when your code is running, the <SomeComponent> type-parameter no longer exists, and your code therefore can't do any operations (if/else, etc) based on its value.

    In other words:

    So, yes, unfortunately you still need to pass a Class object along, or something similar (see "Super Type Tokens" for example), if you need to do something that depends on the type parameter at run-time.

    The reason the Class workaround works is that it loosely speaking represents the type-parameter, since the type-checker makes sure that its instance fits with the type-parameter, but is an object and thus available at run-time too - unlike the type-parameter.

    Note: The Class-trick doesn't work for type-parameters within type-parameters, such as Class<List<Something>>, since at run-time List<Something> and List<OtherThing> is the same class, namely List. So you can't make a Class token to differentiate between those two types. As far as i remember "Super Type Tokens" can be used instead to fix this (they exploit the fact that there is an exception to erasure: For subclasses of generic classes, the type-parameters used when "extending" the superclass are actually available at run-time through reflection. (there are also more exceptions: https://stackoverflow.com/a/2320725/1743225)).

    (Related google terms: "Erasure", "Reification", "Reified generics")