Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Generic argument extends A or B [duplicate]

Tags:

java

generics

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.

like image 704
SomeNorwegianGuy Avatar asked Apr 15 '14 11:04

SomeNorwegianGuy


People also ask

Can a generic class have multiple generic parameters Java?

Yes - it's possible (though not with your method signature) and yes, with your signature the types must be the same.

Can a generic class have multiple generic parameters?

A Generic class can have muliple type parameters.

What does <? Extends mean in Java?

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.


2 Answers

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?

like image 62
maczikasz Avatar answered Oct 20 '22 00:10

maczikasz


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".

like image 22
Uwe Allner Avatar answered Oct 19 '22 22:10

Uwe Allner