I have some problems implementing a Java feature.
I have a list of Sensors. I have different kinds of them, they all extend the base class Sensor.
I have some abstract functions in the base class, and I want these functions to take an Enum as a parameter. The problem is that the Enum is unique for each sub class, and therefore, I can't declare the Enum in the base class.
The code below has Enum as parameter. I know it's not legal syntax, but I just want to illustrate that this is where I want to have the sub class Enum as parameter.
private Vector<Sensor> sensors;
public abstract class Sensor {
public Sensor() {}
public abstract int getParam(Enum param);
public abstract void setParam(Enum param, int value);
}
public class TempSensor extends Sensor {
// Parameter names
public static enum TEMP_PARAMETERS{ PARAM_ALARM_HI, PARAM_ALARM_LO }
public TempSensor() {}
#Override
public int getParam(TEMP_PARAMETERS param) {
// Will do some stuff here
return 0;
}
#Override
public void setParam(TEMP_PARAMETERS param, int value) {
// Will do some stuff here
}
}
If the different Enums implement an interface, I can use the interface as the parameter type in the abstract methods, but then I can pass Enums that don't belong to the respective class as parameter. Is there a way to avoid that?
Looks like you want contradictory things. The whole point of using polymorphism is to take advantage of the substitution principle.
If you want to have a class hierarchy and be sure the right type is entered to the right object, you may consider using the factory pattern.
I strongly recommend against inheritance on Enums; Java doesn't handle that well.
You're on the right track. Assuming you have a marker interface called MyEnumTypeInterface, just have your different enums implement that inferface. Then use MyEnumTypeInterface as the type of the formal parameter for your methods that accept the enum. However, you need to ensure that you're getting an enum that implements MyEnumTypeInterface and not just any other class that implements MyEnumTypeInterface:
public <E extends Enum<E> & MyEnumTypeInterface>void getParam(E e)
This ensures that the formal parameter is an enum and that it implements MyEnumTypeInterface; the methed won't accept as a parameter, another class that also implements MyEnumTypeInterface.
So your classes end up looking like this:
public interface MyEnumTypeInterface {
}
public abstract class Sensor {
public Sensor() {}
public abstract <E extends Enum<E> & MyEnumTypeInterface>int getParam(E param);
public abstract <E extends Enum<E> & MyEnumTypeInterface>void setParam(E param, int value);
}
public enum TempEnum extends MyEnumTypeInterface {
PARAM_ALARM_HI,
PARAM_ALARM_LO
}
public class TempSensor extends Sensor {
public TempSensor() {}
#Override
public<E extends Enum<E> & MyEnumTypeInterface>int getParam(E param) {
return 0;
}
#Override
public <E extends Enum<E> & MyEnumTypeInterface>void setParam(E param, int value) {
// Will do some stuff here
}
}
So you want each Sensor to work a particular param type? That would mean making Sensor generic.
public abstract class Sensor<P extend Enum<P>> {
public Sensor() {}
public abstract int getParam(P param);
public abstract void setParam(P param, int value);
}
There are probably bigger problems with you design. Fixing those could remove the requirement for the get and set.
Related
Consider the following code
#Test
public void testFunction() {
// This cause error
callDoSomething(new myInterfaceImpl());
}
public interface myInterface {
int doSomething();
}
public class myInterfaceImpl implements myInterface {
public int doSomething() {
return 1;
}
}
public void callDoSomething(Class<? extends myInterface> myVar) {
System.out.println(myVar.doSomething());
}
On this line callDoSomething(new myInterfaceImpl()); I get the following error.
Error:(32, 25) java: incompatible types: com.myProject.myTest.myInterfaceImpl
cannot be converted to java.lang.Class<? extends com.myProject.myTest.myInterface>
How do I satisfy the parameter type? If only an interface is provided to me.
I want to bound the class that has an interface, but it seems like this is not avaiable to me
Class<? implements myInterace>
Edit:
The reason I want to do this is because I want to provide a custom kafka partitioner.
public Builder<K, V> withCustomPartitionner(Class<? extends Partitioner> customPartitioner) {
this.customPartitioner = customPartitioner;
return this;
}
It looks like you want to be able to call methods on the parameter that's given. In that case, you'll want the actual instance of your interface, not the Class associated with it.
public void callDoSomething(myInterface myVar) {
System.out.println(myVar.doSomething());
}
Class<> is used when you want to use reflection to do something with the specific class type that you're interested in:
public void outputClassInfo(Class<? extends myInterface> myClass) {
System.out.println(myClass.getName());
}
If that's what you're going for, you'll want to provide the class at compile time like this:
outputClassInfo(myInterfaceImpl.class);
Or, if you won't know which class you're dealing with until runtime, you can use reflection:
myInterface thing = getThing();
outputClassInfo(thing.getClass());
So, in the example you're providing in your edit, I'm guessing you want:
public Builder<K, V> withCustomPartitioner(Class<? extends Partitioner> customPartitioner) {
this.customPartitioner = customPartitioner;
return this;
}
// Usage
builder
.withCustomPartitioner(FooPartitioner.class)
...
This type Class<? extends myInterface> myVar corresponds to a Class instance not to an instance of myInterface.
You generally don't pass a class as parameter (but for reflection purposes or to bypass generics erasures). So what you need as parameter is probably :
public void callDoSomething(myInterface myVar) {
System.out.println(myVar.doSomething());
}
That you could invoke :
#Test
public void testFunction() {
// This cause error
callDoSomething(new myInterfaceImpl());
}
The parameter to callDoSomething shouldn't be a class. It must be an instance of that class or it's subclass.
public <T extends myInterface> void callDoSomething(T myVar) {
System.out.println(myVar.doSomething());
}
On a side note, don't name Java classes/interfaces starting with lower case.
As rightly mentioned by Andy Turner#, there is no need to use a type parameter here and you can just refer to the type as myInterface
public void callDoSomething(myInterface myVar) {
System.out.println(myVar.doSomething());
}
You need to pass the Class not an instance.
callDoSomething(MyInterfaceImpl.class);
I've got generic interface Operand:
public interface Operand<T extends Operand<T>> {
T add(Operand<T> op);
T sub(Operand<T> op);
T mul(Operand<T> op);
T div(Operand<T> op);
}
which is implemented by 2 classes:
public class DoubleOperand implements Operand<DoubleOperand> {
...
}
public class RationalOperand implements Operand<RationalOperand> {
...
}
I've written "factory" interface implemented by DoubleOperandFactory and RationalOperandFactory classes:
public interface OperandFactory {
<T extends Operand<T>> Operand<T> valueOf(String s);
}
public class DoubleOperandFactory implements OperandFactory{
#Override
public Operand<DoubleOperand> valueOf(String s) { ... }
}
public class RationalOperandFactory implements OperandFactory {
#Override
public Operand<RationalOperand> valueOf(String s) { ... }
}
In my program I use an enum which objects store instance of the particular Factory:
public enum OperandType {
DOUBLE(new DoubleOperandFactory()), RATIONAL(new RationalOperandFactory());
private OperandFactory fact;
OperandType(OperandFactory fact){ this.fact = fact; }
public OperandFactory getFact() { return fact; }
}
Now I'm getting message warning "Unchecked overriding" on both factory classes, due to unchecked conversion and I'm pretty confused about this. First thing which I tried is (as it was most commonly answered here in similar topics) to replace generic method with generic factory interface, but finally it turns into impossibility to use them with the enum which should return particular factory, without <?>, as I have to create a List of operands (of generic type T extends Operand<T> for now) and fill it with the objects produced by selected factory. What would be the best way to reorganize this code?
public interface OperandFactory {
<T extends Operand<T>> Operand<T> valueOf(String s);
}
This interface does not do what you think it does.
This interface advertises that an instance of it can generate any type of operand you want. It doesn't just generate one particular kind of operand. It generates all of them.
This is not what you actually have.
What you need instead is
public interface OperandFactory<T extends Operand<T>> {
T valueOf(String s);
}
...and then to give up on the enum, because you can't have enums that have different types in them like that. That's just not a thing you're allowed to do in Java.
I have an interface ServiceArgument which defines a size() promise.
public interface ServiceArgument {
public int size ();
}
Some of my enum types implement this interface
public enum StringCode implements ServiceArgument {
FOO,
BAR,
BACON,
public int size() {
return values().length;
}
}
Some of my class follow a EnumService abstract class.
public abstract class EnumService {
abstract void query (Enum<? extends ServiceArgument> e);
}
And to wrap it up, some class extends this abstract class :
public class ServiceTranslation extends EnumService implements Serializable {
/**some code and ctors and transient stuff etc **/
#Override
void query (Enum<? extends ServiceArgument> e) {
//line that matters :
if (e.ordinal() >= e.size()) {
throw InvalidStringCodeAsked();
}
}
My problem is, I can't use e.size() at the last line, because I wouldn't use FOO.size() in my example enumeration.
Is there a way to, either :
1) specialise what the query method accepts as a parameter in the concrete implementations of EnumService
2) get the concrete type of the Enum called in ServiceTranslation.query(MYSTERIOUS.ENUM), in order to be able to call ConcreteENUM.size(). or even ConcreteEnum.values().length, it's the same.
3) even filter everything that is not from the right enumerated type to throw directly a InvalidEnumeratedTypeException through method override, but i'm not familiar with multiple overriding.
4) something I didn't think of
Edit : #shmosel in the comment is right, even if I get the wrong enumeration as argument, it will never be greater than its size. No point in comparing it to its size.
How about this one?
public abstract class EnumService {
abstract <T extends Enum<T> & ServiceArgument> void query (T e);
}
public class ServiceTranslation extends EnumService implements Serializable {
#Override
<T extends Enum<T> & ServiceArgument> void query (T e) {
if (e.ordinal() >= e.size()) {
throw InvalidStringCodeAsked();
}
}
}
I have the following class hierarchy:
public abstract class Config<T> implements Proxy<T> {
public abstract T parse();
public T get() {....}
}
public class IntegerConfig<Integer> extends Config<Integer> {
public Integer parse() {...}
}
public class LongConfig<Long> extends Config<Long> {
public Long parse() {...}
}
public class IntegerListConfig<List<Integer>> extends Config<List<Integer>> {
public List<Integer> parse() {....}
}
And so on...
I'd like to introduce a new class:
public class ConfigMutation<T> implements Proxy<T> {
public ConfigMutation(....) {
//// create a concrete implementation of Config<T> according to actual parameterized type
}
}
Essentially, I'd like to avoid repeating the entire class hierarchy of Config, and support in ConfigMutation all types that have parameterized implementations in Config class hierarchy.
Couldn't find a way to do it. (Class<T>)((ParameterizedType)getClass().getGenericInterfaces()[0]).getActualTypeArguments()[0] obviously returns T, and not the actual type.
Also, once this problem is solved, I'd be happy if someone could suggest some factory pattern with generic types, so when I'm instantiating a Config derived class inside ConfigMutation, I wouldn't have to do it with a huge if...else block on actual type.
Thanks,
Lior
Change your ConfigMutation class to :
public class ConfigMutation<U,T extends Config<U>> implements Proxy<U> {
public ConfigMutation() {
}
}
You can then use ConfigMutation as :
ConfigMutation<Integer,IntegerConfig> mutation;
You won't be able to do something as follows which is what you want :
ConfigMutation<String,IntegerConfig> mutation;
That said, there is a change you need to make to your concrete Config implementers as well. For example, change IntegerConfig to :
public class IntegerConfig extends Config<Integer> {
public Integer parse() {...}
}
The Integer in IntegerConfig<Integer> will be considered as a type parameter and not the Integer class which is not what you want. (An IDE should give you a warning for this; The type parameter Integer is hiding the type Integer)
I had a question about similar generics yesterday, and as solution I implemented a sort of self-reference in some classes, like this:
public interface Action { }
public interface Result { }
public interface Player<A extends Action, R extends Result, P extends Player<A, R, P>> {
default public void onPostAction(final P target, final A action, final R result) { }
}
abstract public class GesturePlayer<A extends Action, R extends Result, P extends GesturePlayer<A, R, P>> implements Player<A, R, P> { }
abstract public class RPSPlayer extends GesturePlayer<RPSGesture, RPSResult, RPSPlayer> { }
public class RPSHumanPlayer extends RPSPlayer {
#Override
public void onPostAction(final RPSHumanPlayer target, final RPSGesture gesture, final RPSResult result) { }
}
This code does not compile, hoewver I am unable to figure out why.
It does work if in the #Override I use RPSPlayer, however RPSHumanPlayer is simply a subclass of it, should it not work the same as the following?
List<T> list = new ArrayList<>();
Which also has the type definied as the superclass (List resp RPSPlayer), and the referenced object's type as the subclass (ArrayLast resp RPSHumanPlayer).
My aim with this question is to gather insight on how the generics exactly work, and I want to keep the method signature as it is defined in RPSHumanPlayer.
What I think I understand about generics:
T is a typed parameter, like List<String>, etc. Also able to use it for own classes and methods. This also captures all subclasses of T.
? captures all possible Objects. Used to ensure that something is generic and not raw.
? extends T capture a specific subclass of T.
This code is written on Java 8.
In order to achieve the desired method signature in RPSHumanPlayer, you will need to generify RPSPlayer like this:
abstract public class RPSPlayer<P extends RPSPlayer<P>> extends GesturePlayer<RPSGesture, RPSResult, P> { }
Then you can define:
public class RPSHumanPlayer extends RPSPlayer<RPSHumanPlayer>
In Java, parameter types are part of the method signature, so they can't be changed (not even subclassed). Since Java 5, you can use covariant return types, but that's as far as it goes.
Your problem boils down to this:
public interface Player {
default public void onPostAction(Player target) {}
}
public abstract class HumanPlayer implements Player {
#Override
public void onPostAction(HumanPlayer target) {}
}
This cannot work, because onPostAction(HumanPlayer) cannot override onPostAction(Player), because then what would happen if it was called with a Player that was not a HumanPlayer?