Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type Erasure rears its ugly head, how to circumvent?

So I have this interface

public interface EventHandler<E extends EventObject>
{   
    public void handleEvent(E event);
}

and I want to derive classes for it that handle events, like so:

public class WorkingHandler implements EventHandler<MouseEvent>
{
    public void handleEvent(MouseEvent event)
    {
        //handle event
    }
}

Above example works fine. But compiler won't let me implement EventHandler multiple times, due to the extremely frustrating Type Erasure.

public class NotWorkingHandler implements EventHandler<MouseEvent>, EventHandler<KeyEvent>
{
    public void handleEvent(MouseEvent event)
    {
        //handle mouse event
    }

    public void handleEvent(KeyEvent event)
    {
        //handle key event
    }
}

Several questions...

  1. Why does Java not allow Type Erasure? IIRC it is something to do with being compatible with earlier versions of Java, correct?

EDIT: I mean why does Java have Type Erasure (had it the other way around)

  1. Is there any sort of "mod"/"extension" (for lack of a better word) or programming languages that allow me to get around Type Erasure? As I am not using older versions of Java I don't care about my code being compatible with older code.

  2. Are there any workarounds, within the Java language, that I can use to get around Type Erasure?

  3. If no, what are some alternate ways to code event handling in my program that keeps the compiler happy?

like image 202
user1299784 Avatar asked Apr 15 '12 22:04

user1299784


4 Answers

One option is to use a Guava EventBus to post events to subscribers. It's specifically designed to address the issue you're currently facing, among other things.

With it, you don't need to implement any interfaces... just provide two @Subscribe methods like this:

@Subscribe
public void handleKeyEvent(KeyEvent event) { ... }

@Subscribe
public void handleMouseEvent(MouseEvent event) { ... }

Some additional documentation on it is available on the Guava wiki.

like image 136
ColinD Avatar answered Oct 17 '22 19:10

ColinD


Type Erasure is nice because it means that the JVM doesn't need to know anything about Generic types. This also means that there's no performance impact from using Generic types.

Also, your notion about the need to maintain binary compatibility is spot on (as indicated in the Type Erasure tutorial). Type erasure allows code written before Java allowed Generic types to interoperate seamlessly with Java code written using Generics.

How about simply making two handlers and attaching both?

public class KeyHandler implements EventHandler<KeyEvent>
{
    public void handleEvent(KeyEvent event)
    {
        //handle key event
    }
}

public class MouseHandler implements EventHandler<MouseEvent>
{
    public void handleEvent(MouseEvent event)
    {
        //handle mouse event
    }
}
like image 20
ulmangt Avatar answered Oct 17 '22 20:10

ulmangt


I'm not sure that your understanding of Type Erasure in Java is correct. As explained here, the type of your generic class is lost at runtime.

In response to your questions:

  1. I think you are right that Java implements type erasure to enable compatibility with previous versions of the langauge.
  2. No I don't think there is a "mod."
  3. No there are no workarounds (types are removed at compile time), but you can use reflection.
  4. See below.

I think a simpler solution would be to so something like this:

public class WorkingHandler implements EventHandler<EventObject>
{
    public void handleEvent(EventObject event)
    {
        // handle event
        if (event instanceof MouseEvent)
            handleMouseEvent((MouseEvent) event);
        ...
    }

    ...

    private void handleMouseEvent(MouseEvent event)
    {
        // handle mice
    }
}
like image 1
Doddie Avatar answered Oct 17 '22 20:10

Doddie


  1. Yes, type erasure is implemented so that the specifications of the JVM do not have to change in order to run the new version (one implementing generics).

  2. As other pointed out many languages do not implment type erasure. If you are looking within Java, possibly, but I'm not sure -- not it won't work on standard JVMs precisely because of 1.

  3. You can do a generic event handler:

.

public class GenericHandler implements EventHandler<EventObject> 
{ 
  public void handleEvent(EventObject event) 
  { 
    if (event instanceof MouseEvent) {
      MouseEvent mouseEvent = (MouseEvent) event;
      //handle mouse event 
    } else if (event instanceof KeyboardEvent) {
      KeyboardEvent keyboardEvent = (KeyboardEvent) event;
      //handle keyboard event 
    }
  } 
} 

Not the most elegant, but works :)

like image 1
Attila Avatar answered Oct 17 '22 21:10

Attila