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.
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>();
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.
Related
I am new to generics. If I have already created a generic interface IList. But I want to create a method that only works on a list of Students(Student is also another class I created for that problem). Where should I put this method.
P.S. I tried to put this method inside IList class but that doesn't compile since the elements are T rather that Student.
What should I do?
It is not possible to make 'conditional' methods, as in, it is not possible to make a method which only exists for some of the types. A Foo<T> object doesn't change what methods it has based on the T.
You can create a subtype:
public class Foo<T> {
private List<T> elems = ...;
void bar();
}
public class StudentFoo extends Foo<Student> {
void baz() {
for (Student s : elems) {}
}
}
works fine. But that isn't going to magically give all Foo<Student> objects a baz method; you'd have to make them specifically as new StudentFoo(), not as new Foo<Student>().
I am using a generic abstract class of a framework AbstractProcessor<T extends CtElement> which is basically a visitor that visits all elements T. There is a method
public void process(T element)
that acts upon all elements of the specified type and does something.
I then have concrete class implementations of this AbstractProcessor that I create using some sort of factory pattern, while holding a list of the common supertype AbstractProcessor to then call the process-method via polymorphism on them. One of these concrete classes might be smth like XYZProcessor<T extends CtElement> extends AbstractProcessor<T>.
I now create these concrete processors like new XYZProcessor<CtNamedElement>() where CtNamedElement is a subtype of CtElement, so the process-method of the XYZProcessor only gets called with CTNamedElements. But the process-method seems to get called for all visisted elements of type CtElement, NOT only for those of the type CtNamedElement as I want to.
Does anyone know what is happening here?
EDIT: relevant code:
creating processors like this
case CLASS:
//CtClass is subtype of CtNamedElement
this.setProcessor(new AnnotatedWithProcessor<CtClass>(targetName, attributeMappings, metapackage));
break;
Class definition:
public class AnnotatedWithProcessor<T extends CtNamedElement> extends AbstractProcessor<T> {
#Override
public void process(T element) {
//do stuff here with elements of correct type
}
And then calling the processors like this:
//this gets set with a concrete case like above
AbstractProcessor<?> processor;
...
//this astModel gets processed with the respective processor,
//where I expect the process method only getting called for the correct types (in this case only when coming over elements of type CtClass),
//but the method gets called for all types of CtNamedElement, not only for those of type CtClass
this.astModel.processWith(processor);
Seems like you're doing so illegal casting somewhere, but it's hard to tell without seeing more of your implementation. Who is calling XYZProcessor::process? Why do you expect defining a generic interface to perform any sort of filtering?
Going to take a shot in the dark here, but it seems like what you probably want is a lookup map for types versus processors. This kind of code can get messy, so it's a good idea to limit access to this mapping using well tested methods:
private final Map<Class, Object> processorMap = new HashMap<Class, Object>();
public <T extends CtElement> void putProcessor(
Class<T> elementClass,
AbstractProcessor<? extends T> processor
) {
processorMap.put(elementClass, processor);
}
#SuppressWarnings("unchecked")
public <T extends CtElement> AbstractProcessor<? extends T> getProcessor(
Class<T> elementClass,
) {
return (AbstractProcessor<? extends T>) processorMap.get(elementClass);
}
Now when you search for a processor, you can use this map to find the correct implementation to call:
public void <T extends CtElement> process(T element) {
getProcessor(element.getClass()).process(element);
}
You may want to extend this to allow multiple implementations for each class, or filter the processorMap for all valid processors for element.getClass() using Class::isInstance and then processing for each valid key.
I'm using several interfaces with generics types. While combining it together I have some problems when I have to use them from a part of the code that is unaware of the concrete type of the generic parameter.
Suppose I have the following interface:
public interface MyObjectInterface<T extends Number> {}
The object implementing that interfaceare stored in a generic collection with the same generic type:
public interface MyCollectioninterface<T extends Number> {
public void updateObject(MyObjectInterface<T> o);
}
Concrete instances of MyCollectionInterface hold several MyObjectInterface of the same generic parameter:
public class ConcreteCollection<T extends Number> implements
MyCollectionInterface<T> {
List<MyObjectInterface<T>> list;
public void updateObject(MyObjectInterface<T> o){}
}
Now, I have several questions on how to use these generic interfaces from a client class that is
(and must be) unaware of the concrete type of generics.
Suppose I have the following class:
public class ClientClass{
private MyCollectionInterface<?> collection; //1st possibility
private MyCollectionInterface collection; //2nd possibility
public ClientClass(MyCollectionInterface<?> collection){
this.collection = collection;
}
public void foo(MyObjectInterface<?> o){
this.collection.updateObject(o); //this doesn't compile
}
public void foo(MyObjectInterface<? extends Number> o){
this.collection.updateObject(o); //this doesn't compile either
}
public void bar(MyObjectInterface o){
MyObject b = o; //warning
this.collection.updateObject(o); //this compile but with warnings
}
}
First Question :
Considered the fact that ClientClass doesn't care of which concrete type extending Number is the collection, should I declare collection with or without "?" ? If I use the second version I get the following warning:
MyCollectionInterface is a raw type. References to generic type
LatticeInterface should be parameterized
Second Question :
Why method foo doesn't compile?
Third question:
It seems that I need to use bar signature to call updateObject method. Anyway this solution produce a warning while trying to assign the MyObjectInterface parameter, like in the first question. Can I remove this warning?
Last questions:
Am I doing something weird with this generic interfaces and I should refactor my code?
Do I really have to care about all these warnings?
How can I use safety a generic interface from a class where I don't know its concrete type?
Ok, I played a bit with your code and reached a conclusion.
The problem is that your ConcreteCollection (and its interface MyCollectionInterface) declare the method updateObject as receiving an argument of type MyObjectInterface<T> (where T extends Number) - note that the type is a concrete one (not a wildcard).
Now, in your client class you are receiving a collection and storing it as MyCollectionInterface<?> but the instance that is passed to ClientClass' constructor will be of a concrete type, for instance:
new ClientClass(new ConcreteCollection<Integer>());
This means that the method updateObject of that instance would only accept an argument of type MyCollectionInterface<Integer>.
Then, in method foo you are trying to pass a MyObjectInterface<?> to updateObject, but since the compiler doesn't know which generic type your collection accepts (it could be Integer like in my example but it could also be Double or any other type that extends Number), it won't allow any object to be passed.
Long story short, if you declare your reference as MyCollectionInterface<?> you won't be able to call updateObject on it. So you have two choices:
1) Pick a concrete type and stick with it:
private MyCollectionInterface<Number> collection;
public ClientClass(MyCollectionInterface<Number> collection){
this.collection = collection;
}
public void foo(MyObjectInterface<Number> o){
this.collection.updateObject(o); //compiles
}
But then you are limiting the collections you can receive in your constructor (which may not be a bad idea), or:
2) Modify your interface to accept a wildcard type:
public interface MyCollectionInterface<T extends Number> {
public void updateObject(MyObjectInterface<? extends Number> o);
}
public class ConcreteCollection<T extends Number> implements MyCollectionInterface<T> {
List<MyObjectInterface<T>> list;
public void updateObject(MyObjectInterface<? extends Number> o) {}
}
private MyCollectionInterface<?> collection;
public ClientClass(MyCollectionInterface<?> collection){
this.collection = collection;
}
public void foo(MyObjectInterface<?> o){
this.collection.updateObject(o); //compiles
}
Also, note that even in 2) you could still run into the same problem in your implementation of the updateObject method unless you declare your list something like this (with ArrayList for example):
List<MyObjectInterface<? extends Number>> list = new ArrayList<MyObjectInterface<? extends Number>>();
In which case you could as well remove the <T extends Number> from MyCollectionInterface and ConcreteCollection since T isn't used anymore.
#Your last questions:
1) Probably yes
2) You should
3) You can't, if you don't really care which objects you store in the collection, you should ditch generics altogether.
Sorry for the long answer, hope this helps.
I just wonder what usage the following code has:
public class Sub extends java.util.ArrayList<String> {...}
There is no any compiling restriction on the generic constraint java.util.ArrayList<String>.
The compiler does place restrictions on other code based on the type parameter in this case.
This will compile
public class Sub extends java.util.ArrayList<String> {
void addTwice(String s) { this.add(s); this.add(s); }
}
but this will not
public class Sub extends java.util.ArrayList<String> {
void addTwice(Object x) { this.add(x); this.add(x); }
}
Let's say you were making an index for a book, but you don't know how many indices you will need. You could make a class BookIndex extends ArrayList<String> or if you want to get really picky: BookIndex extends ArrayList<IndexEntry>.
/e1
Also, when a one Class extends a generic Class like ArrayList<String> you can grab the String out from the generic declaration, unlike if you had a class ArrayList<T>. In ArrayList<T> you would never be able to figure out what the T is.
You can extend class ArrayList, but it is not something that you should normally do.
Only ever say "extends" when you can truthfully say "this class IS-A that class."
Remember, Its not a good practise to extend the standard classes
Why not use like this ?
public class Sub {
List<String> s = new ArrayList<String>();
// ..
// ...
}
If you do that you can add to the basic functionality of an ArrayList or even change its normal functionality.
For example, you can override the add() method so that it will only add emails to the list.
How can I have an abstract enum, or some kind of base enum?
In my common code I'd like a notion of an enum placeholder, MyItems, without tying myself to a concrete enum. Then in each of my projects I would have a concrete implementation.
E.g.
Common Code
public interface MyItems {
// Marker interface
}
Project A
public enum Items implements MyItems {
RED_CAR, BLUE_CAR, GREEN_CAR;
}
Project B
public enum Items implements MyItems {
BROWN_TREE, GREEN_TREE;
}
This seems to work, but in my common code I can't write a loop over my interface enum, since it's not an enum. In my common code I'd like to write
for (MyItems item : MyItems.values())
doSomething(item);
but I can't because my interface is just a marker interface, and it doesn't have a .values().
Any suggestions greatly appreciated. I don't know if I'm trying in completely the wrong way.
It doesn't really make sense to do this - because the values() method is static. To call it, you need to know the type you want to call it on.
The closest you could come would be to have:
public interface MyItemsFactory<T extends MyItems>
{
Iterable<T> values();
}
and then implement that in some generic way, e.g.
public class EnumFactory<T extends Enum<T> & MyItems>
implements MyItemsFactory<T>
{
private final Class<T> clazz;
public EnumFactory(Class<T> clazz)
{
this.clazz = clazz;
}
public Iterable<T> values()
{
return EnumSet.allOf(clazz);
}
}
But the basic rule is that polymorphism and static methods don't mix. In your call:
for(MyItems item : MyItems.values())
doSomething(item);
which implementation of MyItems would you expect it to iterate over? You could have loads of types implementing MyItems.
You could look into replacing the enums with the Type Safe Enum Pattern, which would allow you to implement an interface, with a values() method that returned all the values for a particular implementation.
Get the class and dig the values with Class.getEnumConstants() from it.