The most important points have already been mentioned:
- Use
double
instead of int
for the coordinates
- Make the fields
private
Concerning the recommendation to make the class immutable, I have to say that one has to really consider the possible application cases here. The Escape Analysis has significantly been improved in the recent Java versions. But for performance-critical applications, having to create possibly millions of objects may still have an impact on performance due to garbage collection (as long as there are no real value types in Java).
Apart from this possible performance impact, one should consider the intended semantics of such a class. Should such a vector really be used like a value, or should it be possible to pass a reference to another class, and let this class change the vector via this reference?
The div
method is rather unusual: I can not imagine an application case where you want to do a component-wise division of the coordinates. Instead, you should consider adding operators with scalars:
public void mul(double factor) {
this.x *= factor;
this.y *= factor;
}
(note that you don't need a div
method with a scalar, because you can simply call vector.mul(1.0/factor)
to achieve the same result).
Concerning the intention to use this in a particle system / physics engine, you should consider introducing additional methods that are required frequently in such a context. For example,
public double lengthSquared() {
return this.x*this.x+this.y*this.y;
}
public double length() {
return Math.sqrt(lengthSquared());
}
public void normalize() {
mul(1.0/length());
}
// When the vectors are interpreted as points,
// you'll often need these:
// (Updated based on the comments: This is
// basically the length of the difference of
// the two vectors)
public double distanceSquared(Vector other) {
double dx = this.x - other.x;
double dy = this.y - other.y;
return dx*dx+dy*dy;
}
public double distance(Vector other) {
return Math.sqrt(distanceSquared(other));
}
The actual set of operations (and their implementation, also in view of the question about immutability) will depend on how you intend to use this class.
But regardless of these usage-based methods: You should consider to implement the hashCode
and equals
methods. Otherwise, the following code would print false
...
Vector v0 = new Vector(1,2);
Vector v1 = new Vector(1,2);
System.out.println(v0.equals(v1));
...although it would be reasonable to yield true
here. An implementation of these methods could look like this:
@Override
public int hashCode() {
long bits = 1L;
bits = 31L * bits + Double.doubleToLongBits(x);
bits = 31L * bits + Double.doubleToLongBits(y);
return (int) (bits ^ (bits >> 32));
}
@Override
public boolean equals(Object object)
{
if (object == null) return false;
if (this == object) return true;
if (!(object instanceof Vector)) return false;
Vector other = (Vector)object;
return this.x == other.x && this.y == other.y;
}
add()
andsub()
? \$\endgroup\$:)
\$\endgroup\$