1

How can I program my class to accept both Integers and Floats, I suppose I'll need to use generics, am I correct?

public class Vec2 {

private int x, y;

public Vec2(int xa, int ya) {
    this.x = xa;
    this.y = ya;
}
public Vec2() {
    this(0, 0);
}
public Vec2(Vec2 vec) {
    this(vec.x, vec.y);
}

public void addX(int xa) {
    x+=xa; // I get an exception here when I try to use generics.
}
public void addY(int ya) {
    y+=ya; // I get an exception here when I try to use generics.
}

Any ideas how to program my class to accept floats, integers and doubles altogether?

julian
  • 4,634
  • 10
  • 42
  • 59

6 Answers6

1

For the time being, we cannot have generics over primitives like int or double, so you will be forced to use boxed representations. It really is easier to just make a separate class for int and double. But if you want to use generics, here's how you can do it in a type-safe way (using java8):

public class Vec2<T> {

    private final BinaryOperator<T> adder;

    private T x, y;

    private Vec2(BinaryOperator<T> adder, T x, T y) {
        this.adder = adder;
        this.x = x;
        this.y = y;
    }

    public void addX(T xa) {
        x = adder.apply(x, xa);
    }

    public void addY(T ya) {
        y = adder.apply(y, ya);
    }

    public static Vec2<Integer> ofInt(Integer x, Integer y) {
        return new Vec2<>(Integer::sum, x, y);
    }

    public static Vec2<Double> ofDouble(Double x, Double y) {
        return new Vec2<>(Double::sum, x, y);
    }
}

Vec2<Integer> intvec = Vec2.ofInt(5, 3);
intvec.addX(8);

Vec2<Double> dblvec = Vec2.ofDouble(5.2, 8.9);
dblvec.addY(-.9);
Misha
  • 27,433
  • 6
  • 62
  • 78
0

No, you don't, merely have your class inherit from Number and use type checking to ensure that values are of the appropriate class, if necessary, e.g.

Class IsraelG99sClass {
    Number n;

    public Number add(Number n2) {
        if (n instanceof Integer && n2 instanceof Integer) {
             return new Integer(n.intValue() + n2.intValue());
        } else { 
             return new Double(n.doubleValue() + n2.doubleValue());
        }
    }

    public Number getValue() {
        if ((n instanceof Integer) || (n instanceof Float)) {
              return n;
        } // handle the other case as appropriate
   }
}
hd1
  • 33,938
  • 5
  • 80
  • 91
0

You could use BigDecimal to back your Vec2 and then you could use create addX and addY method(s) for long and double fairly easily. Something like,

public class Vec2 {
    private BigDecimal x, y;

    public Vec2(double xa, double ya) {
        this.x = BigDecimal.valueOf(xa);
        this.y = BigDecimal.valueOf(ya);
    }

    public Vec2(long xa, long ya) {
        this.x = BigDecimal.valueOf(xa);
        this.y = BigDecimal.valueOf(ya);
    }

    public Vec2(Vec2 vec) {
        this.x = vec.x;
        this.y = vec.y;
    }

    public void addX(double xa) {
        x = x.add(BigDecimal.valueOf(xa));
    }

    public void addX(long xa) {
        x = x.add(BigDecimal.valueOf(xa));
    }

    public void addY(double ya) {
        y = y.add(BigDecimal.valueOf(ya));
    }

    public void addY(long ya) {
        y = y.add(BigDecimal.valueOf(ya));
    }

    @Override
    public String toString() {
        return String.format("x = %s, y = %s", x.toString(), y.toString());
    }
}
Elliott Frisch
  • 198,278
  • 20
  • 158
  • 249
  • I see what you're saying, but BigDecimals are notorious memory hogs, and his question was about how to apply generics. – Michael Macha May 19 '15 at 02:02
  • @MichaelEricOberlin OP did include *Any ideas how to program my class to accept floats, integers and doubles altogether?* Only type that can do that is `BigDecimal`. – Elliott Frisch May 19 '15 at 02:03
  • @ElliottFrisch I liked the idea, not sure if I am going to use it, but the man who downvoted your answer totally got it all wrong, I will up vote it. Thank you. – julian May 19 '15 at 02:29
  • @ElliottFrisch Number will also let you do so. – hd1 May 24 '15 at 23:26
-1

Floats and ints are very different values with vastly different mins and maxes. I would try using doubles as the data member with overloaded constructors for different variable types instead of generics unless generics are really needed.

Ethan Z
  • 208
  • 3
  • 13
-1

Yes, you can use generics and make your x and y attributes of type T.

But you won't be able to just implement the addX and addY in they way you want.

Check these other answers on how to implement a generic number addition, it's not as simple but you should be able to do it that way.

Java Generics and adding numbers together

how to write a generic method for adding numbers

Community
  • 1
  • 1
eugenioy
  • 11,825
  • 28
  • 35
-2

First of all, I'm operating under the assumption that you want x and y to be of varying (generic) type.

For this, you would want:

public class Vec2<E extends Number> {

private E x, y;

public Vec2(E xa, E ya) {
    this.x = xa;
    this.y = ya;
}

//Not _easily_ possible with generics, as the compiler has no guarantee that
//zero is an acceptable value. Consider some variation of a Factory pattern,
//but this will work. Note that there is an "officially"-unchecked cast warning.
public Vec2() {
    super();

    final Number zero = 0.0; 
    this.x = (E)zero;
    this.y = (E)zero;
}

public Vec2(Vec2<E> vec) {
    this(vec.x, vec.y);
}

public void addX(E xa) {
    Number c = x.doubleValue() + xa.doubleValue();
    x = (E)c;
}

public void addY(E ya) {
    Number c = y.doubleValue() + ya.doubleValue();
    x = (E)c;
}

This should work well. While I encourage you to use generics, note that keeping a numeric type (like int, float, or double) as a generic is often not advisable, as they're only similar on the surface. When you dig into the operations of, say, "+", they are radically different dependent on type. You will also have an assortment of unchecked-cast warnings in this code; perhaps I could have rooted them out properly had I the time, but this just goes back to my warning about generic numbers.

You will also notice a few flukes of the language doing this, such as the way that (E)zero works, but (E)(0.0) does not.

By and large, though, generics are a much easier and cleaner way to go about things than inheritance, when it is possible.

Michael Macha
  • 1,729
  • 1
  • 16
  • 25
  • This will break as soon as you try to expose `x` or `y` as `E`. – Sotirios Delimanolis May 19 '15 at 02:02
  • How would it break? E is the declared generic type. Just use `public E getX()`; from the outside it will be the generic. – Michael Macha May 19 '15 at 02:05
  • 4
    If you declare a `Vec2 vec;` and use `vec.getX()`, you'd be expecting an `Integer`, but you'd get back a `Double`, assuming that you had previously used your `addX`. That will cause a `ClassCastException`. – Sotirios Delimanolis May 19 '15 at 02:07
  • Ah, good call. I suppose the other option would be to select a method based on the class of the parameter; but this is really one more reason why I recommend against using generics for numbers. – Michael Macha May 19 '15 at 02:15
  • @SotiriosDelimanolis Yep, just figured it out, well I'll go with using double instead of using generics, seems more safe and flexible at the moment. – julian May 19 '15 at 02:53