2

I'm attempting to create an ArrayList (so java, obviously) with type TileEntity (yes this is a minecraft mod). But I also need the objects added to the ArrayList to implement a certain interface.

The first option that came to mind was creating an abstract subclass of TileEntity that implemented interface, and using that as the ArrayList type. But given the fact that people normally create their own subclasses of TileEntity and use those as the class they normally subclass, and I want people to be able to hook into my mod, I can't expect them to subclass anything besides TileEntity.

My current solution is to check if(object instanceof MyInterface) before adding, but that seems ugly. Surely there's a way to set the type of an ArrayList to require that an object be both a subclass of TileEntity and an implementor of MyInterface.

dcernahoschi
  • 14,968
  • 5
  • 37
  • 59
Will Fancher
  • 245
  • 3
  • 10

2 Answers2

6

You can make generic the method or class where the ArrayList is used. For example, a generic method:

public <T extends TileEntity & MyInterface> void doStuffWith(T obj) {
    List<T> yourList = new ArrayList<T>();
    yourList.add(obj);
    ...//more processing
}

And a generic class:

public class ArrayListProcessor<T extends TileEntity & MyInterface> {
   List<T> theList;

   public void processList(T obj) {
      theList.add(obj);
      ...
   }

   public void someOtherMethod() {
      T listElem = theList.get(0);
      listElem.callMethodFromTileEntity();//no need to cast
      listElen.callMethodFromMyInterface();//no need to cast
   }
}

...//somewherein your code
//SomeObj extends TileEntity and implements MyInterface 
ArrayListProcessor<SomeObj> proc = new ArrayListProcessor<SomeObj>(); 
dcernahoschi
  • 14,968
  • 5
  • 37
  • 59
  • +1. Multiple bounds are discussed in this Java tutorial http://docs.oracle.com/javase/tutorial/java/generics/bounded.html – Andy Thomas Apr 02 '13 at 21:44
  • Perfect! Thanks. I was unaware generics had this ability. – Will Fancher Apr 02 '13 at 22:01
  • Hm... Actually, I'm having a problem now. The arraylist is actually an instance variable, and I can't have the class use a generic type, because then only the T my class was initialized with can be added. Although, having it this way on the method used to add to the arraylist works. Just means I have to cast to my interface all over the place in the class. – Will Fancher Apr 02 '13 at 22:17
  • I don't understand. Why casting? The object should already implement `MyInterface`. Post some sample code from the class: the method and where you need to cast. – dcernahoschi Apr 02 '13 at 22:30
  • Well it's pretty simple. I can't give a generic type to the whole of the class because then I'm bound to one class for T. So therefore I can only create an ArrayList of an existing type. So I have to choose between TileEntity and MyInterface. So everywhere in the class except the method that adds the object to the list has to cast to MyInterface when I want to use the interface methods. Sorry I can't post code. I'm away from the dev environment right now. – Will Fancher Apr 02 '13 at 22:35
  • In my opinion this need for casting to both `TileEntity` and `MyInterface` is one more reason to make the class generic in T. I'll update the answer shortly. – dcernahoschi Apr 02 '13 at 22:56
  • agreed but that simply isn't an option. I can't declare 'myobj = new MyClass();' because I need to be able to add instances of any subclass of TileEntity & MyInterface, not just instances of someclass. – Will Fancher Apr 02 '13 at 23:06
  • I understand now. Maybe you can refactor such that the `ArrayList` is removed from the class and here you just process an `ArrayList` elem. Just thinking... – dcernahoschi Apr 02 '13 at 23:25
0

You could add whatever methods of TileEntity you need to your interface, and just make the ArrayList of your interface. There is probably some fancy way of using generics to solve the problem in a better way, but I'm unsure how.

EDIT: dcernahoschi's solution is much better.

Nora Powers
  • 1,597
  • 13
  • 31