Is it possible to iterate through several enum classes? - java

I have three enum classes. I want to somehow put these in an array, loop through the array and call the same method in each enum class. Is this possible in Java?
It seems to me you can't place enum types in an array structure (unless i've missed how).
Thank you.

Let each enum type implement a common interface that has the common method that you want into invoke. You can now cast each enum, while iterating, to this common interface and call the method. Also look at EnumSet

Here is an example with 2 enums and using reflection:
enum Colour{
RED,
BLUE,
GREEN;
public void foo(){
System.out.println("COLOUR");
}
}
enum Fruit {
APPLE,
BANANA,
PEAR;
public void foo(){
System.out.println("FRUIT");
}
}
You can put the classes into an array and use reflection to call a method for each enum constant:
//create an array
Class[] arr = new Class[2];
arr[0] = Colour.class;
arr[1] = Fruit.class;
//call the foo method
for(Class c : arr){
Method m = c.getMethod("foo", null);
for(Object o : c.getEnumConstants()){
System.out.println("Invoking foo on:" + o);
m.invoke(o, null);
}
}

If, by enum classes, you mean three different enums, each with their own elements, then you can use an array of type Enum[]. If you mean three items from a single enum, let's call it enum X, then you would put them in an array of type X[].
If you are trying to call a standard Enum function on each one, then you should be all set. If you need to call your own function on them, and are going with an array of Enum[], you'll either need to use reflection or have them all implement the same interface.

Related

Generic list conversion to an array

Assuming that I have the following class
public class A <T>{
private T [] datas;
// more code here ...
}
And I desire to take advantage of the constructor to initialize the array. Suppose that I have the following constructor
public A(T element){....}
Java does not allow me to use something like
datas = new T[10]
And it will complain that I cannot create a generic array of T
But I can still use a work around like:
#SuppressWarnings("unchecked")
public A(T element){
List<T> datasList = new ArrayList<T>();
datasList.add(element);
datas =(T[]) datasList.toArray();
}
I have a warning from the compiler that's why I had to add the #SuppressWarnings, but my point is related to the following comment from the toArray method documentation (Please take a look at the picture)
It talks about the returned array being safe. So does that means it is safe to use this method? If not why? And what would be a better way to do such an initialisation in a constructor? I would like to also consider the case of a variable list of T elements in an overloaded constructor like
public A(T... elements){....}.
You can create an instance of a generic array using the following:
public A(T element){
int length = 10;
datas = (T[])Array.newInstance(element.getClass(), length);
}
However, there's a problem if element would be a subclass of T, e.g. if you'd call it like this:
A<Number> numberA = new A<>( Integer.valueOf(1) );
Here T would be Number but the class of element would be Integer.
To mitigate that you could pass a vararg array of type T, e.g. like this:
//firstElement only exists to force the caller to provide at least one element
//if you don't want this then just use the varargs array
A(T firstElement, T... furtherElements){
int length = 10;
Class<?> elementClass = furtherElements.getClass().getComponentType();
datas = (T[])Array.newInstance( elementClass, length);
}
Since varargs always result in an array (even of length 0) you'll get an array of type T and can get the component type of that.
So in the case above numberA.datas would be a Number[] array and not an Integer[] array.
You can pass generics, but you can't call new T (or new T[ ]).
Keep in mind that generics are gone after compilation, so it actually only helps when writing the code. Knowing it's gone during runtime, it's also obvious that new T( ) can't be called as generic, T is removed in runtime.
It's safe to do, because you create that list in full control, accepting only objects of your generic type.
A nicer way (imho) is to create a static method as it is purely input-->output. You have to declare your generics before the method return type:
public < T > T[ ] toArray(T... objects) { ... }

Get enum values from Enum object

If I were to declare an enum like so
public enum Foo {A, B, C}
then I can get the enum values using
Foo[] values = Foo.values();
However if I wanted to pass Foo as a generic type, like so, I can't get the values since it's generic.
class Bar<E extends Enum<E>> {
public Bar(E e) {
E[] values = e.values(); // not possible
}
}
Is it possible to iterate over the enum values any other way?
You'll have to pass the Class object:
public Bar(Class<E> clazz) {
E[] values = clazz.getEnumConstants();
}
...or, if you have one element e of the enum, you might be able to use e.getDeclaringClass().getEnumConstants(). (Don't use e.getClass().getEnumConstants(), which won't work if your enum constants define their own constant-specific methods.)
Another option: EnumSet.allOf(clazz), which is actually more efficient than clazz.getEnumConstants() in many ways, since it's O(1) and not O(n) in the number of enum constants.

Constructor with different ArrayList type as parameter

I't first time i've occourred in this "strange" situation. I need to create two different constructor for my class:
public OpponentListAdapter(Context c, ArrayList<MyCustomObject> l){}
and
public OpponentListAdapter(Context c, ArrayList<String> l){}
because depending by type of generics of ArrayList, i need to perform different actions.
But i have this error:
Method OpponentListAdapter(Context, ArrayList) has the same erasure >OpponentListAdapter(Context, ArrayList) as another method in type OpponentListAdapter
What's wrong?
Maybe the solution it's simple, but for now, i can't find nothing good!
Both the ArrayList<String> and ArrayList<MyCustomObject> have same erasure ArrayList. Thus, both the constructors will have same signature at runtime, and hence that exception, as you have a duplicate constructor there.
If you want the constructor to take different types of ArrayList, then you can either use unbounded wildcard as in:
public OpponentListAdapter(Context c, ArrayList<?> l) {}
that will work for both the array lists, or make your constructor generic, giving a type parameter.
You have two constructors with the same signature, constructor1(Context, ArrayList), constructor2(Context, ArrayList), meaning the constructors are the same.
As an alternative, your OpponentListAdapter could have a public static "creator"-methods. This would look like this:
public class OpponentListAdapter {
// A constructor is not necessary but you could have one if you want
public OpponentListAdapter(Context c, ArrayList<String> l){
...
}
//now the creator method
public static OpponentListAdapter create(Context c, ArrayList<MyCustomObject> l){
// implement the creation here and return it
}
}
This way you have still type safety. This pattern is used fairly often and names for the methods are usually something like:
create()
of() // popular example is List.of() from Java 9+
from()
In your case you could have e.g. 2 different static functions:
createFromString(Context c, List<String> l)
createFromMyCustomObject(Context c, List<MyCustomObject> l)
Calling it would look something like this:
...
List<String> ls = ...
List<MyCustomObject> lo = ...
OpponentListAdapter adapterFromStrings = OpponentListAdapter.createFromStrings(c, ls);
OpponentListAdapter adapterFromMyObject = OpponentListAdapter.createFromObjects(c, lo);
...

Generic method, multiple brackets, types

http://docs.oracle.com/javase/tutorial/java/generics/genmethods.html
Quoting from there-
A more realistic use of generic methods might be something like the following, which defines a static method that stuffs references to a single item into multiple boxes:
public static <U> void fillBoxes(U u, List<Box<U>> boxes) {
for (Box<U> box: boxes {
box.add(u); }
}
Here, what does this List<Box<U>> do? How does this work?
Further,
To use this method, your code would look something like the following:
Crayon red = ...;
List<Box<Crayon>> crayonBoxes = ...;
The complete syntax for invoking this method is:
Box.<Crayon>fillBoxes(red, crayonBoxes);
I couldn't understand all these.
You can think of U as a kind of placeholder for a Type or Interface.
If you have a class Foo and replace all U's in the method declaration with Foo, it will take an instance of Foo and a List>.
As the name "Generic" says, it is a generic way of "replacing" the generic type argument U with a real type. This way you can force that everyone who uses an object of Type U also has to use a List> to call the method.
Taking the Foo example, I can only call
public static <U> void fillBoxes(U u, List<Box<U>> boxes) {
with
Foo foo = new Foo();
List<Box<Foo>> fooList = new ArrayList<Box<Foo>>();
fillBoxes(foo, fooList);
List is a generic collection.
Box is another generic.
You can declare Box<Crayon> to construct a Box of Crayons
List<Box> is a collection of Boxes but Box is generic, need a Type for the box List<Box<Crayon>>.
Just follow the generic type U. FillBoxes method is static public static <U> void fillBoxes(U u, List<Box<U>> boxes). Static methods doesn't need a instance, if there is not a instance you can't declare the type of the box Box<Crayon>, you have to pass the type in the call of the method Box.<Crayon>fillBoxes, knowing that type, the compiler knows that the first parameter in FillBoxes (U u) is a Crayon type and the second is a List of Boxes of Crayons (List<Box<U>> boxes).
The method will fill a list of Crayon Boxes with red crayons :)
Ufff this was hard for a non Java programmer and non native english speaker...
List<Box<U>> simply means it's a list of boxes where you can store U-type objects in each of them.
If for example you have classes "crayon", "pencil", "pen" etc. implementing interface "U", you can store their instances in such boxes.

In Java, is it possible to use a type variable, as an array element, inside an Interface?

In Java, is it possible to use a type variable, as an array element, inside an Interface?
I've tried as a filed type and as a cast operator, but always get the error
Cannot make a static reference to the non-static type A
interface ITest<A> {
A[] j; // Cannot make a static reference to the non-static type A
Object[] = (A[]) new Object[3]; // Cannot make a static reference to the non-static type A
}
Is there any case, where I am able to use the construct A[] inside the interface (and in an enum type?)?
class CTest<A> {
enum MyEnum {
F, G, H;
// something that uses A[] inside. Getting the same error as above
}
}
You can use a generic array type in an interface, like this:
public interface Foo<T> {
void doSomething(T[] array);
}
Your problem was you were trying to declare a field in an interface, which you basically can't do other than for constants. You can't declare a field of a generic array type in an interface, but I'd hope that you wouldn't want to anyway.
Admittedly type erasure makes the combination of arrays and generics somewhat awkward in various situations, but I think the above at least answers the question you posed.
Fields in interfaces are implicitly public, static and final, they're basically constants. And you can't have constants that depend on a type parameter because in Java parameters are removed from the type on compilation.
By the way, this is independent of whether you're using an array or not,
public interface X<T> {
T c = (T)new AnyType();
}
won't work either. And neither would
public class X<T> {
public static final T c = (T)new AnyType();
}

Categories