In Java, we have generics and Generic arguments may be specified to have to extends/implement a certain class/interface.
class MyClass<T extends Number>
One can also specify that it has to implement several interfaces
class MyClass<T extends Number & Comparable>
My question is; how can I specify that a generic argument must extend one of two classes?
Class MyClass<T extends JComponent OR JFrame>
What I have is a Propery
class, which at this time look like this.
public abstract class Property<T> {
public abstract void set(JComponent component, T value);
public abstract void set(JFrame component, T value);
public abstract T get(JComponent component);
public abstract T get(JFrame component);
public static Property<Integer> HEIGHT = new Property<Integer>() {
@Override
public void set(JComponent component, Integer value) {
component.setSize(component.getWidth(), value);
}
@Override
public Integer get(JComponent component) {
return component.getHeight();
}
@Override
public void set(JFrame component, Integer value) {
component.setSize(component.getWidth(), value);
}
@Override
public Integer get(JFrame component) {
return component.getHeight();
}
};
public static Property<Integer> WIDTH = new Property<Integer>() {
@Override
public void set(JComponent component, Integer value) {
component.setSize(value, component.getHeight());
}
@Override
public Integer get(JComponent component) {
return component.getWidth();
}
@Override
public void set(JFrame component, Integer value) {
component.setSize(value, component.getHeight());
}
@Override
public Integer get(JFrame component) {
return component.getWidth();
}
};
...
}
Although, more properties, like BACKGROUND_COLOR, and LOCATION.
The problem really starts here, as you may be able to se the duplicate code for every property, but it gets worse in the Animation class:
public class Animation {
public static void callbackAnimation(AnimationCallback callback, double duration, double fps) {
double timeout = (1/fps)*1000;
int iterations = (int)(duration/timeout);
for (int i = 0; i <= iterations; i++) {
callback.run((double)i/(double)iterations);
try {
Thread.sleep((long)timeout);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void animateProperty(final JComponent component, final Property<Color> property, Color to, double duration, double fps) {
final Color currentValue = property.get(component);
final int differenceRed = to.getRed() - currentValue.getRed();
final int differenceGreen = to.getGreen() - currentValue.getGreen();
final int differenceBlue = to.getBlue() - currentValue.getBlue();
final int differenceAlpha = to.getAlpha() - currentValue.getAlpha();
Animation.callbackAnimation(new AnimationCallback() {
@Override
public void run(double fraction) {
Color newColor = new Color(
(int)(currentValue.getRed()+(differenceRed*fraction)),
(int)(currentValue.getGreen()+(differenceGreen*fraction)),
(int)(currentValue.getBlue()+(differenceBlue*fraction)),
(int)(currentValue.getAlpha()+(differenceAlpha*fraction))
);
property.set(component, newColor);
}
}, duration, fps);
}
public static void animateProperty(final JFrame component, final Property<Color> property, Color to, double duration, double fps) {
final Color currentValue = property.get(component);
final int differenceRed = to.getRed() - currentValue.getRed();
final int differenceGreen = to.getGreen() - currentValue.getGreen();
final int differenceBlue = to.getBlue() - currentValue.getBlue();
final int differenceAlpha = to.getAlpha() - currentValue.getAlpha();
Animation.callbackAnimation(new AnimationCallback() {
@Override
public void run(double fraction) {
Color newColor = new Color(
(int)(currentValue.getRed()+(differenceRed*fraction)),
(int)(currentValue.getGreen()+(differenceGreen*fraction)),
(int)(currentValue.getBlue()+(differenceBlue*fraction)),
(int)(currentValue.getAlpha()+(differenceAlpha*fraction))
);
property.set(component, newColor);
}
}, duration, fps);
}
}
I stripped out some methods, but you should get the idé. I have to write every single method twice, once for JFrame and once for JComponent, which is a pain.
Yes - it's possible (though not with your method signature) and yes, with your signature the types must be the same.
A Generic class can have muliple type parameters.
The extends keyword extends a class (indicates that a class is inherited from another class). In Java, it is possible to inherit attributes and methods from one class to another. We group the "inheritance concept" into two categories: subclass (child) - the class that inherits from another class.
I don't think that's possible, well it doesn't make sense to have that construct.
When you specify your parameters using A & B then you know that you will be able to call the methods of A and B on the instance that you have, but if you would be able to specify A OR B then it would be ambiguous to the compiler whether you can call A.a() or you can call B.b();
If you have the need for such a construct you're likely to have design issues, post your code and we might be able to help
Seeing your code, maybe you should use an Adapter around the JFrame and JComponent that will hide the duplicated code, though JFrame and JComponent are both Container, can you not use that?
This is not possible; you can only do that implicit, if you specify a common baseclass of these both classes. Generics are made to know what's inside. And that does not mean "one or the other".
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With