Using interface methods of enum in method accepting class - java

I have a method that needs to accept a Enum class. These enums implement an interface. Now I need access to both Enum methods like ordinal(), name(), etc and my interface methods. What I've tried:
public <T extends ConfigFeature, Enum> void showEnabledFeatures(Class<T> enumType, long mask) {
List<T> list = Arrays.asList(enumType.getEnumConstants());
list.forEach(item -> {
// My interface's method, works fine
item.getMask();
// Enum method doesn't work:
// item.ordinal();
});
}
Reversing the order reverses the working:
public <T extends Enum, ConfigFeature> void showEnabledFeatures(Class<T> enumType, long mask) {
List<T> list = Arrays.asList(enumType.getEnumConstants());
list.forEach(item -> {
// My interface's method, doesn't work now
// item.getMask();
// Enum method now works:
item.ordinal();
});
}
Is there a way to get access to both methods from interface and Enum?

You are using the wrong syntax to say that T must implement this interface AND is an enum.
This:
<T extends ConfigFeature, Enum>
is not constraining T to Enum, but actually creating a new generic parameter called Enum.
Similarly,
<T extends Enum, ConfigFeature>
is not constraining T to ConfigFeature. You are declaring a new generic parameter called ConfigFeature.
The correct syntax is to use &:
<T extends Enum<T> & ConfigFeature>
Note that the order is actually important here! Enum can only come first.
According to here, only the first constraint can be a class, and then the ones after it must all be interfaces:
TypeParameter:
{TypeParameterModifier} Identifier [TypeBound]
TypeParameterModifier:
Annotation
TypeBound:
extends TypeVariable
extends ClassOrInterfaceType {AdditionalBound}
AdditionalBound:
& InterfaceType

Your syntax is wrong; you need:
public <T extends Enum<T> & ConfigFeature>
That syntax that you used creates two generic type parameters one called T and one called Enum (where Enum isn't bounded and T is bounded to extend ConfigFeature).
Note that, to avoid any generics warnings about the use of raw types, you also have to provide a type parameter to the Enum bound. An enum called X always extends Enum<X>, so you can use T extends Enum<T>, and the full text of the method local generic declaration becomes <T extends Enum<T> & ConfigFeature>

Replace the , in your second example with &. You can use & to declare multiple bounds as long as they’re interfaces from the second type onwards. If you use a comma it’s a separate type parameter, not a bound.

Just to add to existing answers, instead of using Mutliple Bounds as described in other answers, you can define interface that combines interface you want with return method for enum, like:
public interface ConfigFeatureEnumI <T extends Enum<T>> extends ConfigFeatureI{
#SuppressWarnings("unchecked")
default public T asEnum() {
return (T) this;
}
}
You can implement asEnum() in enum used, or just use default method if Java 8 is available as I show here.
public enum ConfigEnum implements ConfigFeatureEnumI<ConfigEnum>{//...
Then showEnabledFeatures can look like:
public <T extends ConfigFeatureEnumI<?>> void showEnabledFeatures(Class<T> enumType, long mask) {
List<T> list = Arrays.asList(enumType.getEnumConstants());
list.forEach(item -> {
// Interface method works:
item.getMask();
// Enum method works via asEnum():
item.asEnum().ordinal();
});
}
While adding new Interfaces is not ideal, it can be easier to use for programmers who do not know Java generics that well or never used Multiple bounds (I use generics a lot, but never needed such feature , so I was a bit off when I did see it).

Related

Wildcards as method attributes in java

Is it possible to use wildcards as an attribute itself and not as a type parameter?
public void doSomething(<? extends Context> myObject){
}
I want to make sure that my object extends Context and also implements a certain interface.
Using wildcards as a return type is valid but using it as an attribute seems to not work
public <? extends MyClass> validMethod(){
}
Yes it's possible, you have to define it before the return type.
public <T extends MyClass> void myMethod(T param);
You don't explicitly state (for your case) which is the interface and which is the class, but if you wanted to have a generic type bound to both extending a class and an interface, this would be the general form for it.
public <T extends Number & Comparable<T>> T findNumber(List<T> elements) { }
Number is an abstract class; Comparable is an interface. I believe what you have to specify them in this order - concrete before interface.

Generic return type of enum-method

Situation: May Field be a property of a Model which I want to observe (something similar to PropertyChangeListener). Field is defined as Enum. I want to call
someModel.getField(Field f).addObserver(FieldObserver<Something> observer)
the Observer's type ("Something") depends on the Field and I want to force typesafety. For example Field.FIRST_NAME would take a FieldObserver< String>.
First (working) approach:
I could already reach it by defining Field as generic class with public static final fields, instead of enum. So I have a Field, which I can use to force type safety like this:
public <E> Observable<E> getField(Field<? extends E> f)
with method in Observable<E>: void addObserver(FieldObserver<? super E> observer)
Now the following line causes a compile time error, which is what I want:
someModel.getField(Field.some_STRING_field).addObserver(INTEGERObserver)
Second (not working yet) approach:
I am trying now to implement the same behaviour with the enum class. One of my approach is:
public enum Field{
FIRST_NAME("firstName") {
#Override
public Observable<String> getObservable() {
return new Observable<String>();
}
},...
//every Field must implement:
public abstract FieldObservable.Observable<?> getObservable();`
}
//getField(Field f) of the Model-class:
public Observable<?> getField(Field f){
return f.getObservable();
}
Trying to add a FieldObserver of any type (also the correct one) gives me a compile time error like this:
addObserver (enumer.FieldObserver< capture< ?>>) in Observable cannot be applied
to (enumer.FieldObserver< java.lang.String>)
Can someone tell me how to make the enum-approach work? Also if someone has a better solution or concerns about the approaches, I will be thankful to hear it.
Unfortunately enums cannot be generic. This is because enum is an ordinary class that extends Enum, i.e. its definition looks like the following:
class MyEnum<E extends Enum<E>> extends Enum<E extends Enum> {}
So application programmer cannot add more generic parameter to this class.
I can suggest you the following work arounds:
Make your method generic, ie. define it in enum level as public <T> getField(Class<T> type). Override this method for each enum member. Then you can supply the type at any call of the method.
Do not use enum for this task. Create ordinary class with public static members and private constructor. if you want enum-like behavior implement your own static values() and valueOf().

Java: How can I pass a value representing an Enum class?

Motivation: I would like to construct an enum that represents all possible values for some family of values (I hesitate to say "class" here). The enum will have additional methods, fields, and perhaps even implement other interfaces. I would then like to pass this enum to another method, where it will iterate over all of the possible values (using Enum.values() and do some work.
I've researched and found that enum Foo actually becomes Foo extends Enum<Foo>. This is why I cannot extend an enum. I have tried to define my method arguments as:
myMethod(Class<?> bar) {...}
myMethod(Class<? extends Enum> bar) {...}
myMethod(Class<? extends Enum<?>> bar) {...}
but inside the method when I try something basic like:
int i = bar.values().length;
it fails. Is there some other way I can do this (or avoid the need to do this)?
Note: I could pass an actual instance of the enum and use bar.getDeclaringClass() to find the enum class (rather than an instance) but this is pretty ugly.
Try using the following:
<E extends Enum<E>> void myMethod(Class<E> enumType) {
E[] values = enumType.getEnumConstants();
...
}
From the getEnumConstants() documentation:
Returns the elements of this enum class or null if this Class object
does not represent an enum type.
Edit: if you're using different enum types implementing a shared interface, you can modify your method in order to be able to call the interface methods. For example:
interface Fooable {
void foo();
}
...
<E extends Enum<E> & Fooable> void myMethod(Class<E> enumType) {
E[] values = enumType.getEnumConstants();
for (E value : values) {
value.foo();
}
}

How to declare a Class<?> object such that is is an Enum AND an Interface in Java

I have a utility class that needs to work on a generic Class but must be restricted to those that are an enum and implement a particular interface.
// These two work
Class<? extends Enum<?>> enumClass;
Class<? extends MyInterface> interfaceClass;
// This is what I want but does not work
Class<? extends MyInterface & Enum<?>> enumAndInterfaceClass;
For generics I can successfully use this
public class MyClass<T extends Enum<T> & MyInterface> {
public MyClass(Class<T> theClass) {
...
}
}
However I can't use the Generics everywhere and need to declare it separately. I am not sure if this is even possible.
So my question boils down to how can I declare a member variable with those constraints?
So Currently MyClass is a singleton then as needed the enum/interface can be updated. The return values of its operations will change depending on which enum it is given. I would like to not have the generics on it since that would require creating a new instance for every change to the enum. There is a lot of code using it already so deviating from the singleton is not going to be approved. So a reference must be kept. I suppose I could only enforce the Interface requirement then check in the setter method that it is an enum throwing an exception otherwise but that is not ideal.
Edit (Updated question and added more detail)
As far as I remember, you can only declare intersection types (this is what & creates) for type parameters of classes and methods. You can not declare a local variable with an intersection type directly; you can create such variables with the aid of a class or method type parameter, as seen in the answer of milkplusvellocet.
See the JLS reference in this answer to a similar question:
https://stackoverflow.com/a/6643378/282229
This should work:
public interface MyInterface {
void foo();
}
public final class Utils {
public static <E extends Enum<E> & MyInterface> void doWork(Class<E> clazz) {
for(E enumConstant : clazz.getEnumConstants) {
enumConstant.foo();
}
}
}
EDIT I didn't notice your line about using the captured type as a local variable. You can of course use this throughout the body of the parameterised method, see revised snippet above.

Java Collections using wildcard

public static void main(String[] args) {
List<? extends Object> mylist = new ArrayList<Object>();
mylist.add("Java"); // compile error
}
The above code does not allow you to add elements to the list and wild cards can only be used as a signature in methods, again not for adding but only for accessing.
In this case what purpose does the above fulfil ??
Let's say you have an interface and two classes:
interface IResult {}
class AResult implements IResult {}
class BResult implements IResult {}
Then you have classes that return a list as a result:
interface ITest<T extends IResult> {
List<T> getResult();
}
class ATest implements ITest<AResult> {
// look, overridden!
List<AResult> getResult();
}
class BTest implements ITest<BResult> {
// overridden again!
List<BResult> getResult();
}
It's a good solution, when you need "covariant returns", but you return collections instead of your own objects. The big plus is that you don't have to cast objects when using ATest and BTest independently from the ITest interface. However, when using ITest interface, you cannot add anything to the list that was returned - as you cannot determine, what object types the list really contains! If it would be allowed, you would be able to add BResult to List<AResult> (returned as List<? extends T>), which doesn't make any sense.
So you have to remember this: List<? extends X> defines a list that could be easily overridden, but which is read-only.
In his book great 'Effective Java' (Second Edition) Joshua Bloch explains what he calls the producer/consumer principle for using generics. Josh's explaination should tell you why your example does not work (compile) ...
Chapter 5 (Generics) is freely available here: http://java.sun.com/docs/books/effective/generics.pdf
More information about the book (and the author) are available: http://java.sun.com/docs/books/effective/
With java generics using wildcards, you are allowed the above declaration assuming you are only going to read from it.
You aren't allowed to add/write to it, because all generic types must be stripped at compile time, and at compile time there isn't a way the compiler knows List are only strings, (it could be any object including strings!)
You are however allowed to read from it since they are going to be at least objects. Mixing different types are not allowed in java collections to keep things clean and understandable, and this helps ensure it.
The point of bounded wildcard types is their use in method signatures to increase API flexibility. If, for example, you implement a generic Stack<E>, you could provide a method to push a number of elements to the stack like so:
public void pushAll(Iterable<? extends E> elements) {
for(E element : elements){
push(e);
}
}
Compared to a pushAll(Iterable<E> elements) signature without a wildcard, this has the advantage that it allows collections of subtypes of E to be passed to the method - normally that would not be allowed because an Iterable<String> is, somewhat counterintuitively, not a subclass of Iterable<Object>.
This works:
List<? super Object> mylist = new ArrayList<Object>();
mylist.add("Java"); // no compile error
From O'Reilly's Java Generics:
The Get and Put Principle: use an extends wildcard when you only get values our of a structure, use a super wildcard when you only put values into a structure, and don't use a wildcard you both get and put.
List<? extends Object>, which is the same as List<?>, fulfills the purpose of generalizing all types List<String>, List<Number>, List<Object>, etc. (so all types with a proper type in place of the ?). Values of all of these types can be assigned to a variable of type List<?> (which is where it differs from List<Object>!).
In general, you cannot add a string to such a list. However, you can read Object from the list and you can add null to it. You can also calculate the length of the list, etc. These are operations that are guaranteed to work for each of these types.
For a good introduction to wildcards, see the paper Adding Wildcards to the Java Programming Language. It is an academic paper, but still very accessible.
Java Generics : Wild Cards in Collections
extends
super
?
Today I am going to explain you how the wild cards are useful. To understand this concept is bit difficult
Now Suppose you have abstract class and in that you have abstract method called paintObject().
Now you want to use different type of collection in every child class.
This below is AbstractMain Method.
Here Steps we have taken for this Abstract Main method
1. We have created abstract class
2. In Parameter we have define T(you can use any character)
--In this case whichever class implement this method it can used any type of class.
ex. Class can implement method like
public void paintObject(ArrayList object) or public void paintObject(HashSet object)
3. And We have also used E extends MainColorTO
-- In this case E extends MainColorTo
-- It's clearly means whichever class you want to use that must be sub class of MainColorTo
4. We have define abstract method called paintObject(T object,E objectTO)
--Now here whichever class is implement method that method can use any class on first argument and second parameter that method has to use type of MainColorTO
public abstract class AbstractMain<T,E extends MainColorTO> {
public abstract void paintObject(T Object,E TO);
}
Now we will extend above abstract class and implement method on below class
ex.
public class MainColorTO {
public void paintColor(){
System.out.println("Paint Color........");
}
}
public class RedTO extends MainColorTO {
#Override
public void paintColor() {
System.out.println("RedTO......");
}
}
public class WhiteTO extends MainColorTO {
#Override
public void paintColor() {
System.out.println("White TO......");
}
}
Now we will take two example.
1.PaintHome.java
public class PaintHome extends AbstractMain<ArrayList, RedTO> {
#Override
public void paintObject(ArrayList arrayList,RedTO red) {
System.out.println(arrayList);
}
}
Now in above PaintHome.java you can check that we have used ArrayList in first argument(As we can take any class) and in second argument we have used RedTO(Which is extending MainColorTO)
2.PaintCar.java
public class PaintCar extends AbstractMain<HashSet, WhiteTO>{
#Override
public void paintObject(HashSet Object,WhiteTO white) {
System.out.println(Object);
}
}
Now in above PaintCar.java you can check that we have used HashSet in first argument(As We Can take any class) and in second argument we have used WhiteTO(Which is extending MainColorTO)
Ponint to Remember
You can not use super keyword at class level you can only use extends keyword at class level defination
public abstract class AbstractMain<P,E super MainColorTO> {
public abstract void paintObject(P Object,E TO);
}
Above code will give you compiler error.

Categories