Ok i have two enums:
public enum AnotherEnum
{
value1, value2, value3;
}
public enum MyEnum implements MyInterface
{
value1(AnotherEnum);
generic_reference_type a;
MyEnum ( ?? )
{
a = ??
}
GetGenericReference()
{
return this.a;
}
}
I want MyEnum to store a reference to the AnotherEnum class so I'll be able to do this:
MyEnum.value1.GetGenericReference().values();
Is this possible?
If I'm reading your question correctly. you would like to pass a different generic type to each instance of an enum... well you can't do that, because every instance of an enum is from the same class, which can be generic, but if generic must have the same generic parameter.
However, you can get something close to your intention by basing your code around an enum class, which is expressed as Class<? extends Enum<?>>:
public enum AnotherEnum {
A, B, C;
}
public enum YetAnotherEnum {
X, Y, Z;
}
public interface MyInterface {
public Enum<?>[] getGenericReferenceValues();
}
public enum MyEnum implements MyInterface {
value1(AnotherEnum.class),
value2(YetAnotherEnum.class);
final Class<? extends Enum<?>> a;
private MyEnum(Class<? extends Enum<?>> a) {
this.a = a;
}
public Enum<?>[] getGenericReferenceValues() {
return a.getEnumConstants();
}
}
And to see it working:
public static void main(String[] args) {
System.out.println(Arrays.toString(MyEnum.value1.getGenericReferenceValues()));
System.out.println(Arrays.toString(MyEnum.value2.getGenericReferenceValues()));
}
Output:
[A, B, C]
[X, Y, Z]
If you don't know the class, you get get the values of a generic enum with reflections
Object someEnum = ...
// get all the values for the same Enum type.
Object[] enums = someEnum.getClass().getEnumConstants()
Related
I have the following code
import java.util.Arrays;
public class CustomEnum {
//?? varName;
public <E extends Enum<E>> CustomEnum(Class<E> enumClass) {
System.out.println(Arrays.toString(enumClass.getEnumConstants()));
//?? varName = enumClass;
}
}
public enum Mode {
SAMPLE_A,
SAMPLE_B,
SAMPLE_C,
SAMPLE_D
}
and I can call it in this way
public static void main(String[] args) {
CustomEnum customEnum = new CustomEnum(Mode.class);
}
code output
[SAMPLE_A, SAMPLE_B, SAMPLE_C, SAMPLE_D]
What I want to do is assign the value of enumClass to a variable and assign it in the constructor but I don't know which type the variable should be, I tried with multiple ways but I get compilation errors, is this possible?
if the above is not possible, how could I convert a generic type
E[] which is returned by getEnumConstants() to a String[]?
Make the whole class generic, not just the constructor.
public class CustomEnum<E extends Enum<E>> {
private E[] constants;
public CustomEnum(Class<E> enumClass) {
constants = enumClass.getEnumConstants();
}
}
I have several enums which implement an interface I've defined. Now I'd like to provide some boilerplate operations on these enums based on their common interface as well as their common enum ancestry. Is this possible?
In other words, I have:
public enum Car implements Vehicle {
FORD, HONDA;
}
public interface Vehicle {
String getLicensePlate();
}
And I'd now like to write something like this, perhaps in a default interface method or some other common place:
public static showLicensePlates(Vehicle.class vEnum) {
for(Vehicle v : vEnum.values()) {
System.out.println(v.getLicensePlate());
}
}
Notice how I'm relying on enum's "values()" method, so the interface must be an enum for this to work. How can I specify that this interface must be an enum? Or if that's not possible, how an I write boilerplate methods to operate on enums in general?
What you want is for the showLicensePlates() method to only take an argument that is both a vehicle and enum. This is done with generics:
public <T extends Enum & Vehicle> showLicensePlates(T vEnum) {
//do stuff
}
Can call
Vehicle.class.getEnumConstants()
If it does not return null,then its an enum.
Java doc says:
Returns the elements of this enum class or null if this Class object does not represent an enum type.
Since you have the interface and the Enumerator implemets such... then you can adapt the enum to return some Ids and...
interface Vehicle {
String getLicensePlate();
}
enum Car implements Vehicle {
FORD("F-007"), HONDA("H-860");
private final String id;
private Car(String id) {
this.id = id;
}
#Override
public String getLicensePlate() {
return this.id;
}
}
...and play with the Constraints in the method ShowLicenseMEthod.
public class Abc {
public static void main(String[] args) {
Abc c = new Abc();
c.showLicensePlates(Car.class);
}
public <E extends Enum<E> & Vehicle> void showLicensePlates(Class<E> vEnum) {
for (E v : vEnum.getEnumConstants()) {
System.out.println(v.getLicensePlate());
}
}
}
Then you can pass ALL the enum classes you have and the method will print the LicensePlates of all the Enum Constants...
I'd like to make a method that implement valueOf on any Enum class passed in parameter (and also wrap some specialized error/missing-name code).
So basically, I have several Enum such as:
enum Enum1{ A, B, C }
enum Enum2{ D, E, F }
And I want a method that wrap around valueOf. I could not find a way to directly pass an Enum class in parameter on which I could call valueOf. Here is what I came up with:
private static Enum getEnum(Class<Enum> E, String name){
for(Enum e: E.getEnumConstants())
if(e.name().equals(name)){
return e;
}
return null;
}
Which I want to call with: getEnum(Enum1,"A"). But it does not like it:
java: cannot find symbol
symbol: variable Enum1
location: class Main
Why implement your own, when you can use Java's own implementation for this?
YourEnum yourEnum = Enum.valueOf(YourEnum.class, value);
http://docs.oracle.com/javase/7/docs/api/java/lang/Enum.html#valueOf(java.lang.Class,%20java.lang.String)
Your method then becomes:
private static <E extends Enum<E>> E getEnum(Class<E> enumClass, String name){
try {
return Enum.valueOf(enumClass, name);
} catch(IllegalArgumentException e) {
return null;
}
}
and you can call it with:
getEnum(Enum1.class, "A")
For pass classes you should use class
getEnum(Enum1.class,"A")
And then update method signature to
private static Enum getEnum(Class<? extends Enum> E, String name){
...
}
I have in mind an interface which declares a method for converting a raw score from a survey to a percentile value for a particular category, where the categories are described by more than one otherwise unrelated enum types. So I started with this:
public interface NormTable<E extends Enum<E>> {
Integer percentileForRawScore(E e, int score);
}
I've then got an implementing class for, say, the Foo survey and its Subscale enum:
public class FooSubscaleNormTable implements NormTable<Subscale> {
public Integer percentileForRawScore(Subscale e, int score) {
// Implementation
}
}
And finally, a factory class for creating the appropriate concrete class:
public class NormTableFactory {
public static <E extends Enum<E>> NormTable<E> normTableForSurveyAndType(
String surveyCode, Class<E> clazz) {
if ("Foo".equals(surveyCode) && Subscale.class.equals(clazz)) {
return (NormTable<E>) new FooSubscaleNormTable();
} else {
// ...
}
}
}
I suspect the cast there is wrong, as Eclipse flags it as unchecked, though lets me carry on. The Java 1.6 compiler on the build server, however, is not happy at all and flags them as inconvertible types.
Have I got the signatures in the factory class wrong, or is my whole architecture looking suspect? I note above that the enum types are "otherwise unrelated", though they all represent categories within surveys, and could conceivably implement an interface to unify their types. Would that help?
You shouldn't use a concrete Enum class in your declaring type.
Make FooSubscaleNormTable generic as well
public class FooSubscaleNormTable<E extends Enum<E>> implements NormTable<E> {
public Integer percentileForRawScore(E e, int score) {
if(e instanceof Subscale) {
switch((Subscale) e) {
case X:
// do something
break;
}
}
// return 0;
}
}
and change your factory to
public class NormTableFactory {
public static <E extends Enum<E>> NormTable<E> normTableForSurveyAndType(
String surveyCode, Class<E> clazz) {
if ("Foo".equals(surveyCode) && Subscale.class.equals(clazz)) {
return (NormTable<E>) new FooSubscaleNormTable<E>();
} else {
// whatever else
}
}
}
Then when you invoke it, that is when you pass in your desired enum type.
NormTable<Subscale> scale = NormTableFactory.normTableForSurveyAndType("surveyCode", Subscale.class);
A and AService are base classes.
B and BService extend these classes.
A and B are beans containing parameters for the services.
BService expects a B typed argument in the execute method.
public class A
{
private int a1;
public int getA1() { return a1; }
public void setA1(int a1) { this.a1 = a1; }
}
public class B extends A
{
private int b1;
public int getB1() { return b1; }
public void setB1(int b1) { this.b1 = b1; }
}
public abstract class AService
{
public int execute(A a)
{
return a.getA1() + getValue();
}
public abstract int getValue(A a);
}
public class BService extends AService
{
public int getValue(A a)
{
B b = (A) a;
return b.getB1();
}
}
Is there a better way to do this code ?
In particular, is there a way to avoid to cast objects ?
It sounds like generics are what you're looking for. Typically, whenever you have a concrete class which can always safely cast a value, you can usually express this via generic parameters (and have it checked at compile time).
In this particular example, you'd declare the AService with a generic parameter which must be some subclass of A. Then you use that parameter to make some methods specific to the particular type - in this case the getValue method, as something like
public class AService<T extends A> {
// Now this takes a T - i.e. the type that a subclass is parameterised on
public abstract int getValue(T a)
// Execute will have to take a T as well to pass into getValue - an A
// wouldn't work as it might not be the right type
public int execute(T a)
{
return a.getA1() + getValue(a);
}
}
where the T is a type parameter (conventionally a single uppercase letter). Then you can declare the BService as
public class BService extends AService<B> {
// The type is checked by the compiler; anyone trying to pass an instance
// of A into this class would get a compile-time exception (not a class cast
// at runtime)
public int getValue(B b) {
return b.getB1();
}
}