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.
Related
I have a coding pattern in java which is some flavor of the strategy pattern. My problem is that the code requires an unchecked cast which I would like to avoid. To explain it briefly, I firstly have a set of classes which share a common interface:
interface IType {}
class TypeA implements IType {}
class TypeB implements IType {}
Then I have a set of strategies which do some specific processing on IType objects.
interface IStrategy<T extends IType> {
specificProcessing(T o);
}
Lastly, I have a singleton which does some generic processing on ITypes, then fetches the proper IStrategy to do the specific processing. The IStrategy objects are registered in map and I think the method signature ensures that only matching pairs of ITypes and IStrategies go into the map.
class Context {
private Map<Class<? extends IType>, IStrategy<? extends IType>> map;
public static Context getInstance() {}
public <T extends IType> void register(IStrategy<T> s, Class<T> c) {
map.put(c, s);
}
public <T extends IType> void genericProcessing(T o) {
//do generic stuff with o
#SuppressWarnings("unchecked")
IStrategy<T> s = (IStrategy<T>) map.get(o.getClass());
s.specificProcessing(o);
}
}
The "problem" is the unchecked cast warning. I know this happens because the declaration of the map allows non-matching pairs of IType and IStrategy. I also know that the code is type safe because of register(). But is there any other design which avoids the unchecked cast?
I would appreciate any input, thanks.
There is no way to avoid it when using this map. I would suggest moving the map access into a separate method, so the code reads more cleanly.
#SuppressWarnings("unchecked")
private <T extends IType> IStrategy<T> getStrategy(T o) {
return (IStrategy<T>) map.get(o.getClass());
}
BTW, you can do it in scala.
Edit:
You can do it in Octarine, see blog on post Extractors. But maybe this is just a fancy way or moving the logic to it's own method, but bringing in a lot of complexity.
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.
I have the following method which takes a list of classes as a parameter:
public List<Interface> getInterfacesOfTypes(List<Class<? extends InternalRadio>> types) {
List<Interface> interfaces = new ArrayList<Interface>();
for(Interface iface : _nodes)
if(types.contains(iface._type))
interfaces.add(iface);
return interfaces;
}
What I want to do is create a wrapper for it where only a single class is specified, which calls the above method with a list of only that one class:
public List<Interface> getInterfacesOfType(Class<? extends InternalRadio> type) {
return getInterfacesOfTypes(Arrays.asList(type));
}
However, I am getting an error:
The method getInterfacesOfTypes(List<Class<? extends InternalRadio>>) in the type InterfaceConnectivityGraph is not applicable for the arguments (List<Class<capture#3-of ? extends InternalRadio>>)
I can't figure out why this is or what the capture #3-of even means. I'd greatly appreciate any help!
Solution
Change the interface to the following:
public List<Interface> getInterfacesOfTypes(List<? extends Class<? extends InternalRadio>> types)
To be quite honest, I cannot really explain why. Broadening the range of allowed generic collections (by adding '? extends') just makes it easier for the compiler to see this is valid...
Aside
Instead of Arrays.asList(type) I would write Collections.singletonList(type).
Prefixing class members with '_' is uncommon in Java
I think Interface is not a great name as 'interface' is also a Java concept (and it seems Interface is not such an interface :) )
I'd probably use an 'getType()' function on Interface instead of directly referring to its '_type' field - this makes for easier refactoring later.
You can probably accept any Collection rather than requiring a List
If you are sure of you object types:
public List<Interface> getInterfacesOfType(final Class<? extends InternalRadio> type)
{
final List list = Arrays.asList(type);
#SuppressWarnings("unchecked")
final List<Class<? extends Interface>> adapters = list;
return getInterfacesOfTypes(adapters);
}
Assuming that I have a basic enum like:
public enum Color { Red, Green, Blue}
How can one write a generic class which only accepts "enum classes" so that a concrete instantiation of that generic class might look like MyClass<Color>?
Edit:
What a actually want to do is to write a generic abstract class containing a function returning all enum "entries" as list:
public abstract class EnumListBean<E extends Enum<E>> {
public List<E> getEnumList() {
return Arrays.asList(E.values());
}
}
While Day.values() is available E.values() is not. What i am doing wrong here?
public class EnumAcceptor<E extends Enum<E>> {
...
}
Use E as a type inside your class.
See Istvan Devai for answer to original question.
For the follow up, methods like values() are static methods, so you're out of luck trying to get that from a generic parameter. As a poor solution, you can pass the enum's Class object into the constructor. and use Class.getEnumConstants. But you might as well pass MyEnum.values() into the constructor rather than the class, and so avoid reflection altogether. It's a real shame there isn't a sensible enum metaclass.
An enum really declares a class derived from Enum. As such, you can use:
public class MyClass<T extends Enum> { }
Note that #Istvan's solution can only accept elements of the enum, which is fine if that is all you want.
Although you cannot pass the enum itself as a parameter (because it does not actually have an object equivalent) you can specify that you must receive the class of the enum in your constructor and derive the enum's details from that:
public class EnumAcceptor<E extends Enum<E>> {
public EnumAcceptor(Class<E> c) {
// Can get at the enum constants through the class.
E[] es = c.getEnumConstants();
}
enum ABC {
A, B, C;
}
public static void main(String args[]) {
EnumAcceptor<ABC> abcAcceptor = new EnumAcceptor<ABC>(ABC.class);
}
}
You can't use E.values() due to type erasure -- the type of E is not available at run-time.
For the specific case in your question, you're probably better off using Guava's Lists.newArrayList:
List<Color> days = Lists.newArrayList(Color.values());
I have created the following interface
public interface ISolutionSpace {
public boolean isFeasible();
public boolean isSolution();
public Set<ISolutionSpace> generateChildren();
}
However, in the implementation of ISolutionSpace in a class called EightQueenSolutionSpace, I am going to return a set of EightQueenSolutionSpace instances, like the following stub:
#Override
public Set<ISolutionSpace> generateChildren() {
return new HashSet<EightQueenSolutionSpace>();
}
However this stub wont compile. What changes do I need to make?
EDIT: I tried 'HashSet' as well and had tried using the extends keyword. However since 'ISolutionSpace' is an interface and EightQueenSolutionSpace is an implementation(and not a subclass) of 'ISolutionSpace', it is still not working.
Two possibilities:
#Override
public Set<? extends ISolutionSpace> generateChildren() {
return new HashSet<EightQueenSolutionSpace>();
}
Or
#Override
public Set<ISolutionSpace> generateChildren() {
return new HashSet<ISolutionSpace>();
}
and simply add instances of EightQueenSolutionSpace to the set.
Mind you, inheritance and other object hierarchy features don't exactly work like expected in generics.
But it's not your only problem : you try to return an ArrayList as an implementation of Set, which can't work !
Concerning the generics part, when you write Set<ISolutionSpace>, you say to the compiler you want a collection of instances of ISolutionSpace, but not of possible subclasses of ISolutionSpace. To be allowed to use subclasses, you'll have to use ? extends ISolutionSpace, which precisely says "accept any subclass of ISolutionSpace".
So, to have a valid code, you'll have to change both your interface and your implementation.
Your interface should become
public interface ISolutionSpace {
public boolean isFeasible();
public boolean isSolution();
public Set<? extends ISolutionSpace> generateChildren();
}
And your implementation
#Override
public Set<? extends ISolutionSpace> generateChildren() {
//for()
return new HashSet<EightQueenSolutionSpace>();
}
return new HashSet<ISolutionSpace>();
All the references in the HashSet can point to EightQueenSolutionSpace instances, but the generic type should be ISolutionSpace.
Set and List are different types of collections.
You could either change your declaration to return a list, or change the return parameter class to an implementation of Set (HashSet, TreeSet...)
According to the Java API:
Interface Set
All Superinterfaces: Collection
All Known Subinterfaces: SortedSet All
Known Implementing Classes:
AbstractSet, HashSet, LinkedHashSet,
TreeSet
I think you have to replace Set with List:
Interface List
All Superinterfaces: Collection
All
Known Implementing Classes:
AbstractList, ArrayList, LinkedList,
Vector
Assuming the caller would in turn work with the generic ISolutionSpace interface rather than the specific EightQueenSolutionSpace, just change the generateChildren method to public Set<? extends ISolutionSpace> generateChildren()
All the types of collection in Java is like this:
Collection
├List
│ ├LinkedList
│ ├ArrayList
│ └Vector
│ └Stack
└Set
Map
├Hashtable
├HashMap
└WeakHashMap
So it's obvious for this error. Try modify Set into List would solve this problem.
Hope this would help you.