Java OOP - Physics Engine type - java

I am trying to create a n-body simulator in Java while also learning OOP.
I want to have a file that contains all physical constants and physics formulas and I want to use these in other classes when calculating forces etc
Should this file be a regular class with all variables static, an interface or an abstract class, or something else? I am quite confused with all the definitions.

In your case I would create a class named Physics or something of that nature. Inside this class you can then accomplish all of the things you want to do by creating static methods and static variables, as JayC667 has pointed out. It should look something like this:
public class Physics {
public static final int GRAVITY_ACCELERATION = 9.58;
public static double formula(double x, double y) { ... }
// etc.
}
Then, to utilize this class from a different one, you simply reference the variables and use the methods like so:
System.out.println("Acceleration of Gravity = " + Physics.GRAVITY_ACCELERATION);
double speed = Physics.formula(23.5, 840);

You use interfaces to force classes (implementing those interfaces) to have defined methods (defined in the interface) you can can ensure basic functionality, while all the classes can be totally different in all other regards.
In an interface, you only define the method signature (return value, name, parameter types). These are purely abstract.
Since Java 8, interfaces can also contain default methods, that may contain code, but can be overridden by the implementing classes.
Best example is the Comparable interface. You can use that for Numbers, Strings, and any other classes that should be comparable (usually to their own class instances aka objects).
Abstract classes are a mixture of regular classes and interfaces. They contain code and member variables, but can also contain abstract methods. When a class extends an abstract base class, they need to implement the abstract methods at some point.
The normal classes do not have any abstract methods.

This is a question Java-developers usually fight over. General rules of thumb are the following:
If you use a static field, always make it final and never try to mutate it.
If you need a mutable field, create a non-static field.
If possible, initialise the field in the constructor and mark it final.
Methods are static only if they access no non-static fields (ie. they do not have a context), there is no need to abstract over them
(for example in a test case) and they are completely functional (this should
be implied by the fact that no static field is mutable). A good example is Math.sqrt(), where the square root operation does not have a context, does not mutate the state of your application and you never want to abstract over it. In all other cases use a non-static method. Some people completely avoid static methods.
Interfaces are most useful when your classes interact with one another. You can specify certain common functionalities available in a group of classes in your application. Then if some of your code requires these functionalities, you can use them without knowing the actual implementation. Say, you handle shapes in a method and want to know the area of a shape. You may have many shapes and you can retrieve the area without knowing the exact type (circle, triangle etc.).
In general, try not to overuse inheritance. Follow the substitution principle: only use inheritance if the superclass could always be substituted by the subclass.
For example: in OOP a square with variable slides is not a rectangle with variable slides, because for rectangles you are allowed to call setSide(20, 30), while for squares you are not (the two sides must match). Note: if you use final fields which are initialized in the constructor, as suggested earlier, this problem is automatically solved and you are free to inherit square from rectangle.
In your case, I would create utility classes with static methods/fields for common functionalities that do not have a context, such as calculating a formula with given input parameters. The actual bodies could be objects with common interface or abstract parent class.

This is some simple example of how you could do it.
Please ignore the aerial resistance part, didn't really think about that, some movements may be funny :-)
import java.util.ArrayList;
/**
* Contains constants and convenience methods
* #author JayC667
*/
class Globals {
static public final float GRAVITY_ACC = -9.81f; // meters per secondĀ²
static public float getTotalSpeed(final float pSpeedX, final float pSpeedY) {
return (float) Math.sqrt(Math.pow(pSpeedX, 2) + Math.pow(pSpeedY, 2));
}
static public float getDistanceBetweenObjects(final PhysicalObjectInterface pObj1, final PhysicalObjectInterface pObj2) {
final float distX = pObj2.getPosX() - pObj1.getPosX();
final float distY = pObj2.getPosY() - pObj1.getPosY();
return getTotalSpeed(distX, distY); // coincidentally same as average speed :-)
}
static public String toString(final PhysicalObjectInterface pObject) {
return pObject.getClass().getSimpleName() + "\tX=" + pObject.getPosX() + "\tY=" + pObject.getPosY();
}
}
interface PhysicalObjectInterface {
default boolean collidesWith(final PhysicalObjectInterface pOther) {
final float distance = Globals.getDistanceBetweenObjects(this, pOther);
return distance < getRadius() + pOther.getRadius();
}
float getPosX();
float getPosY();
float getSpeedX();
float getSpeedY();
float getMass();
float getRadius();
float getAerialResistanceCofactor();
void calcNextCycle();
}
/**
* Does most of the simple work
* #author JayC667
*/
abstract class PhysicalObjectABC implements PhysicalObjectInterface {
private float mPosX;
private float mPosY;
private float mSpeedX;
private float mSpeedY;
public PhysicalObjectABC(final float pPosX, final float pPosY, final float pSpeedX, final float pSpeedY) {
mPosX = pPosX;
mPosY = pPosY;
mSpeedX = pSpeedX;
mSpeedY = pSpeedY;
}
#Override public float getPosX() {
return mPosX;
}
#Override public float getPosY() {
return mPosY;
}
#Override public float getSpeedX() {
return mSpeedX;
}
#Override public float getSpeedY() {
return mSpeedY;
}
#Override public abstract float getMass();
#Override public abstract float getAerialResistanceCofactor(); // could also derive this from radius
// getRadius is not repeated here, but still is abstract and has to be defined in the implementing subclass
#Override public void calcNextCycle() {
final float gravForceY = getMass() * Globals.GRAVITY_ACC; // F = m * a
final float aerialResistForceX = -Math.signum(mSpeedX) * (float) (Math.pow(mSpeedX, 2) * getAerialResistanceCofactor());
final float aerialResistForceY = -Math.signum(mSpeedY) * (float) (Math.pow(mSpeedY, 2) * getAerialResistanceCofactor());
final float totalForceX = aerialResistForceX;
final float totalForceY = gravForceY + aerialResistForceY;
final float accX = totalForceX / getMass(); // a= F / m;
final float accY = totalForceY / getMass(); // a= F / m;
mSpeedX += accX;
mSpeedY += accY;
mPosX += mSpeedX;
mPosY += mSpeedY;
}
#Override public String toString() {
return Globals.toString(this);
}
}
class Stone extends PhysicalObjectABC {
public Stone(final float pPosX, final float pPosY) {
super(pPosX, pPosY, 0, 0);
}
#Override public float getRadius() {
return 0.1f;
}
#Override public float getMass() {
return 1;
}
#Override public float getAerialResistanceCofactor() {
return 0.2f;
}
}
class Leaf extends PhysicalObjectABC {
public Leaf(final float pPosX, final float pPosY) {
super(pPosX, pPosY, 0, 0);
}
#Override public float getRadius() {
return 0.1f;
}
#Override public float getMass() {
return 0.003f;
}
#Override public float getAerialResistanceCofactor() {
return 0.95f;
}
}
class StaticObject implements PhysicalObjectInterface {
private final int mPosX;
private final int mPosY;
private final int mRadius;
public StaticObject(final int pPosX, final int pPosY, final int pRadius) {
mPosX = pPosX;
mPosY = pPosY;
mRadius = pRadius;
}
#Override public float getPosX() {
return mPosX;
}
#Override public float getPosY() {
return mPosY;
}
#Override public float getSpeedX() {
return 0;
}
#Override public float getSpeedY() {
return 0;
}
#Override public float getMass() {
return 0;
}
#Override public float getRadius() {
return mRadius;
}
#Override public float getAerialResistanceCofactor() {
return 0;
}
#Override public void calcNextCycle() { /* ignore, does not move */}
#Override public String toString() {
return Globals.toString(this);
}
}
public class PhysicsEngine {
static private ArrayList<PhysicalObjectInterface> sObjects = new ArrayList<>();
public static void main(final String[] args) {
sObjects.add(new Leaf(10, 100));
sObjects.add(new Stone(20, 100));
sObjects.add(new Leaf(30, 100));
sObjects.add(new Stone(40, 100));
sObjects.add(new StaticObject(30, 100, 1)); // lantern
sObjects.add(new StaticObject(40, 100, 5)); // tree
for (int cycle = 0; cycle < 1000; cycle++) {
simulateCycle(cycle);
printData(cycle);
checkCollisions(cycle);
try {
Thread.sleep(1000);
} catch (final InterruptedException e) { /* ignore */}
}
}
private static void simulateCycle(final int pCycle) {
System.out.println("Simulating cycle #" + pCycle);
for (final PhysicalObjectInterface o : sObjects) {
o.calcNextCycle();
}
}
private static void printData(final int pCycle) {
System.out.println("Printing cycle #" + pCycle);
for (final PhysicalObjectInterface o : sObjects) {
System.out.println("\t" + o);
}
}
private static void checkCollisions(final int pCycle) {
System.out.println("Checking for collisions in cycle #" + pCycle);
final ArrayList<PhysicalObjectInterface> destroyedItems = new ArrayList<>();
for (final PhysicalObjectInterface o1 : sObjects) {
for (final PhysicalObjectInterface o2 : sObjects) {
if (o1 == o2) continue; // ignore IDENTICAL, not equal, items
if (o1.collidesWith(o2)) {
System.out.println("CRASH!\n\tObject 1 (" + o1 + ") \ncollides with \n\tObject 2 (" + o2 + ")");
destroyedItems.add(o1);
destroyedItems.add(o2);
}
}
}
sObjects.removeAll(destroyedItems); // can't delete within loop, would invalidate iterators or migh also f*** up loop indices
}
}

Related

How to declare individual elements in a enum in java?

Hi I am trying to write this piece of code about physics but have a problem.
In fact two problems:
1.the formula for gravitation its throwing a error about using the field .class
2.I want to declare the types of individual variables in a element
I think its clearer if I show the source code:
public class Main
{
public static void main(String[] args) {
}
abstract class Gravitation{
public abstract int Gravitation(int mass[],int dist,int force);
}
class PhySyst{
public int mass;
public int wt;
public float smallG = 9.8f;
//this is the posible value of charge
enum Charge{Positive,Negative,PositiveCoulumb,NegativeCoulumb,IsNegative,IsPositive};
}
class Earth extends Gravitation{
//stores acceleration due to gravity
public float smallG = 9.8f;
//the raduis of earth is needed in the physics formula for distance
public float GravityPressure = 6.67f;
public float raduisofEarth = 6371f;
//this finds the gravation using newtons principles
public int Gravitation(int mass[],int dist,int force)
{
force = (GravityPressure * mass[])/(dist * dist);
return force;
}
}
}
the error is this:
Main.java:32: error: '.class' expected
force = (GravityPressure * mass[])/(dist * dist);
^
1 error
Thanks for reading :)
Couple of Fixes here:
Constants should be static final (#constant).
Gm1m2/r2, formula so rather than array you should pass 2 input params (m1 and m2).
As multiplication is operation for number not array (mass[]).
Enum should be defined in public class or in static class.
As the force can be float, so change the return type to float from current int.
#JsonIgnoreProperties(ignoreUnknown = true)
class Category {
abstract class Gravitation {
public abstract float getGravitationalForce(int mass1, int mass2, int dist);
}
//this is the possible value of charge
enum Charge {
Positive, Negative, PositiveCoulumb, NegativeCoulumb, IsNegative, IsPositive
};
class PhySyst {
public int mass;
public int wt;
public float smallG = 9.8f;
}
class Earth extends Gravitation {
//stores acceleration due to gravity
public static final float SMALL_G = 9.8f; #constant
//the radius of earth is needed in the physics formula for distance
public static final float GRAVITATIONAL_PRESSURE = 6.67f; #constant
public static final float RADIUS_OF_EARTH = 6371f; #constant
//this finds the gravitation using newtons principles
public float getGravitationalForce(int mass1, int mass2, int dist) {
return (GRAVITATIONAL_PRESSURE * mass1 * mass2) / (dist * dist);
}
}
}

How can I access a method of a class from a generic method

I'm working on a tiny exercise java program that calculates circle and square (classes) area, that implements surface (interface) which has a method called area(). A requirement is that I have to implement a class called SumArea that has a generic method called calcArea() that receives Circle circ[] and Square square[] arrays and executes area calculation.
Program structure:
-> UseSumArea.java (main method)
-> Surface.java (interface)
-> Square.java (class that implements Surface.java)
-> Circle.java (class that implements Surface.java)
-> SumArea.java (class that executes calcArea() method)
UseSumArea.java
public class UseSumArea {
public static void main(String[] args) {
Square square[] = { new Square(2.0), new Square(5.0) };
Circle circ[] = { new Circle(3.0), new Circle(2.0) };
Surface surf[] = new Surface[square.length + circ.length];
surf[0] = square[0];
surf[1] = square[1];
surf[2] = circ[0];
surf[3] = circ[1];
SumArea sum = new SumArea();
System.out.println("Square's sum area = " + sum.calcArea(square));
System.out.println("Circle's sum area = " + sum.calcArea(circ));
System.out.println("Surface's sum area = " + sum.calcArea(surf));
}
}
Surface.java
public interface Surface {
public double area();
}
Square.java
public class Square implements Surface {
private double area;
private double side;
public Square(double l) {
this.side = l;
area();
}
#Override
public double area() {
return this.area = (this.side)*(this.side);
}
public double getArea() {
return area;
}
public void setArea(double area) {
this.area = area;
}
public double getSide() {
return side;
}
public void setSide(double side) {
this.side = side;
}
}
Circle.java
public class Circle implements Surface {
private double area;
private double radius;
public Circle (double r) {
this.radius = r;
area();
}
#Override
public double area() {
return area = (((this.radius)*(this.radius))*(Math.PI));
}
public double getRadius() {
return radius;
}
public void setRadius(double raio) {
this.raio = raio;
}
public double getArea() {
return area;
}
public void setArea(double area) {
this.area = area;
}
}
SumArea.java
public class SumArea {
private double area;
public <T> double calcArea(T[] t) { //generic method that receives Square and Circle arrays
double arrayArea = 0;
for (T a : t) {
arrayArea = arrayArea+(a.area());
}
return this.area = arrayArea;
}
}
My doubt is over this SumArea's code snippet:
arrayArea= arrayArea+(a.area());
How can I access the area() method of each Circle and Square objects inside this generic method?
You need to bound the type variable:
public <T extends Surface> double calcArea(T[] t) {
or just declare the parameter as an array of Surfaces:
public double calcArea(Surface[] t) {
Note that the latter is preferable because generics and arrays don't play very nicely together. If you were to need to have a type variable for other reasons, it would be advisable to change to a Collection, or similar:
public <T extends Surface> double calcArea(Collection<T> t) {
(And, as a minor matter of preference, I would use S rather than T to name a type variable which extends Surface)
Since the problem in regard to generic types is already addressed by Andy Turner, I just want to add a suggestion related to the class design.
I think there is a bit of redundancy in how these classes were designed. You need to create an instance of SumArea in order to do the calculation. And the result of the last of the last calcArea() method call will be stored in this object (let's assume that this calculation is far more complex and CPU-consuming).
But do we really need to store somewhere else the value is already returned by the method? In this case, the idea to cash the history of calculations (as a single variable or as a collection of values) doesn't seem to be useful because it can't be reused without knowing which objects were involved in the calculation.
And without storing the result this method will not be bound to a state, i.e. it has to be static. And since interfaces can have static methods, instead of creating a utility class for that purpose it could be placed in the Surface interface. Like that.
public interface Surface {
public double area();
public static <T extends Surface> double calcArea(T[] t) { // generic method that receives Square and Circle arrays
double arrayArea = 0;
for (T a : t) {
arrayArea += a.area();
}
return arrayArea;
}
}
Note that static behavior declared in interfaces in contrast to classes could be invoked only by using the name of an interface:
System.out.println("Circle's sum area = " + Surface.calcArea(circ));
Also note that it makes sense for both classes to have a field area inside the classes Circle and Square only if other fields will be declared as final, i.e. they must be initialed only one during the object construction and setters become unnecessary.
In this case (assuming that radius has been declared as final and is being validated when assigned so that reduce > 0) method area() will look like this:
#Override
public double area() {
if (area > 0) { // `0` is a default value for instance variables
return area; // reusing already calculated value
}
return area = radius * radius * Math.PI;
}
And there mustn't be two methods area() and getArea() leave either one or another.

How to create multiple instances to an implementation of an interface?

Let A be an interface which has a method a.
Let B be a class which implements A and has method a and has three fields 1,2,3.
I want to use two instances of A (meaning B), both of which have different values of 1,2,3 (present in cfg file) at two different places.
Can someone provide a simple and elegant solution to this problem using Guice.
You don't tell how the class that uses your dependency references the interface. I assume that you want to reference it with an interface.
What you can use, is annotation that will denote which instance you want to use. Assume that these are your implementations:
interface A {
void a();
}
class B implements A {
private int value;
void a() { ... }
B(int value) { this.value = value; }
}
And these are the classes that use the implementations:
class UserFirst {
private A a;
#Inject
UserFirst(#Named("first") A a) { this.a = a; }
}
class UserSecond {
private A a;
#Inject
UserSecond(#Named("second") A a) { this.a = a; }
}
The thing that decides which implementation is going to be injected is the #Named annotation. You can also define your annotations, but usually it's an overkill.
Now, in order to bind that, you can do something like this:
class MyModule extends AbstractModule {
#Override
protected void configure() {
A first = new B(1);
B second = new B(2);
bind(A.class)
.annotatedWith(Names.named("first")).toInstance(first);
bind(A.class)
.annotatedWith(Names.named("second")).toInstance(second);
}
}
Here's the full documentation: https://github.com/google/guice/wiki/BindingAnnotations
if I do understand you correctly, you might want to make B abstract so that you can override the methods which you want to change, if this is the case.
Now I can only assume that by fields you mean field-varriables. I would then recommend you to make them NON-static and change them in the constructor when you make an object. Then read the values of 1,2,3 in the public static void main method and send them upon creating a new object:
public class B implements A {
private int x,y,z;
/**
* This would now be the constructror
*/
public B(int x, int y, int z){
this.x = x;
this.y = y;
this.z = z;
}
/**
* Then some return functions
*/
public get1() { return this.x; }
public get2() { return this.y; }
public get3() { return this.z; }
/**
* Then whatever methods you get from A
*/
public int someMethodFromA(int x, int y){
return x*y;
}
}
public static void main(String[] args) {
/**
* Some random method to read inn from CFG file
*/
int x1 = readXFromCFG();
int y1 = readYFromCFG();
int z1 = readZFromCFG();
B objectB1 = new B(x1,y1,z1);
int x2 = readXFromCFG();
int y2 = readYFromCFG();
int z2 = readZFromCFG();
B objectB2 = new B(x2,y2,z2);
int x3 = readXFromCFG();
int y3 = readYFromCFG();
int z3 = readZFromCFG();
B objectB3 = new B(x3,y3,z3);
}

Java: How can I make a ball behave as a bouncing and elastic ball?

I have two classes BouncingBall and another one called ElasticBall. Both classes extends BallImpl which implements an interface called Ball.
public interface Ball {
int DEFAULT_RADIUS = 50;
int radius();
Point center();
void update();
}
public class BouncingBall extends BallImpl {
public static final int MOVEMENT_SPEED = 12;
static final int DOWN = 1;
static final int UP = -1;
private int direction;
BouncingBall(int x, int y, int direction) {
super(x, y);
this.direction = direction;
}
#Override
public void update() {
direction = reverseDirectionIfNecessary();
y = move();
}
private int reverseDirectionIfNecessary() {
if (movingTooHigh() || movingTooLow()) {
return switchDirection();
}
return this.direction;
}
private boolean movingTooLow() {
return y + radius >= BallWorld.BOX_HEIGHT && movingDown();
}
private boolean movingTooHigh() {
return y - radius <= 0 && movingUp();
}
private int switchDirection() {
return movingDown() ? UP : DOWN;
}
private int move() {
return y + (MOVEMENT_SPEED * direction);
}
private boolean movingDown() {
return direction == DOWN;
}
private boolean movingUp() {
return direction == UP;
}
}
public class ElasticBall extends BallImpl {
public static final int GROWTH_RATE = 2;
static final int GROW = 1;
static final int SHRINK = -1;
private int growthDirection;
ElasticBall(int x, int y, int radius, int growthDirection) {
super(x, y, radius);
this.growthDirection = growthDirection;
}
#Override
public void update() {
growthDirection = reverseGrowthDirectionIfNecessary();
radius = next();
}
private int reverseGrowthDirectionIfNecessary() {
if (growingTooBig() || shrinkingTooSmall()) {
return switchDirection();
}
return this.growthDirection;
}
private boolean shrinkingTooSmall() {
return radius <= 0 && shrinking();
}
private boolean growingTooBig() {
return radius >= Ball.DEFAULT_RADIUS && growing();
}
private int switchDirection() {
return growing() ? SHRINK : GROW;
}
private int next() {
return radius + (GROWTH_RATE * growthDirection);
}
private boolean shrinking() {
return growthDirection == SHRINK;
}
private boolean growing() {
return growthDirection == GROW;
}
}
I need to create a BouncingElasticBall which combines the behavior of the BouncingBall and the ElasticBall classes. I have poor knowledge in OOP, and I know Java does not allow multiple inheritance, so how can I solve this problem?
Thanks in advance.
One way you could approach this is to not extend BallImpl, but make sort-of plugins. Like this:
public class BallImpl implements Ball {
List<BallBehavior> behaviors = ...
#Override
public void update() {
behaviors.forEach(behavior -> behavior.update(this));
}
...
}
public interface BallBehavior {
void update(BallImpl ballImpl);
}
And then, just write your elastic and bouncing logic as behaviors.
Once you diverge hierarchies there's no way to merge them in java.
It's a design matter: if you know that ElasticBall and BouncingBall may be combined together, you should create two interfaces Elastic and Bouncing, both extending interface Ball, with common methods valid for both.
Then the common method implementations may be set into a common abstract class, let's say AbstractBall. At this point you can finally detail your three implementations:
ElasticBall extends AbstractBall implements Elastic
BouncingBall extendis AbstractBall implements Bouncing
ElasticBouncingBall extends AbstractBall implements Elastic, Bouncing
In this way you'll be able to control what to do in each method, reuse code for common stuff (in the abstract class).
You can use interfaces that allows multiple inheritance. Make the interface for each ballElasticBall and BouncingBall and implement both of them in BouncingElasticBall.

Is this an immutable class?

I have no idea what immutable class should look like but am pretty sure this one is. Am I right? If I'm not please specify what should be added/removed.
import java.io.Serializable;
public class Triangle implements IShape, Serializable {
private static final long serialVersionUID = 0x100;
private Point[] points;
public Triangle(Point a, Point b, Point c) {
this.points = new Point[]{a, b, c};
}
#Override
public Point[] getPoints() {
return this.points;
}
#Override
public boolean equals(Object obj) {
if (obj == null) return false;
if (this == obj) return true;
if (getClass() != obj.getClass()) return false;
Point[] trianglePoints = ((Triangle) obj).getPoints();
for (int i = 0; i < points.length; i++){
if (!points[i].equals(trianglePoints[i])) return false;
}
return true;
}
}
Will this do the trick?
#Override
public Point[] getPoints() {
Point[] copyPoint = {
new Point(points[0]),
new Point(points[1]),
new Point(points[2]),};
return copyPoint;
}
Point class:
import java.io.Serializable;
public class Point implements Serializable {
private static final long serialVersionUID = 0x100;
public int x;
public int y;
public int z;
public Point(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
public Point(Point that) {
this.x = that.x;
this.y = that.y;
this.z = that.z;
}
public boolean equals(Object obj) {
// assume this is a typical, safe .equals implementation
// that compares the coordinates in this instance to the
// other instance
return true;
}
}
No, you can change what's in the Points array. If you want to make it immutable, have the getter hand out a copy of the Points array, not the original.
try this:
Triangle triangle = new Triangle(a, b, c);
triangle.getPoints()[1] = null;
System.out.println(Arrays.toString(triangle.getPoints()));
Also Point needs to be immutable (as Nikita Rybak points out). For how to copy arrays see how to copy an array in Java.
No, it's not. You expose the Point[] and a caller could modify its contents. Also, your class is not final, so someone could subvert it by subclassing it.
No, it's definitely mutable.
Not only do you expose the actual Point[] array, you don't defensive-copy (Bloch 2nd ed., Item 39) the Point objects themselves when taking them in via the constructor.
The Point[] array could have items
removed or added to it, so it's
mutable.
You could pass in Points a,
b, and c, then call setX() or setY()
on them to change their data after
construction.
Close. For one thing, an immutable class should make it's fields final, but that's not a requirement.
However, you are exposing an array through the getter, and that is not immutable. Make a defensive copy using Arrays.copyOf(array, length):
#Override
public Point[] getPoints() {
return Arrays.copyOf(this.points,this.points.length);
}
Here's what I'd do to make this class immutable, with the help of Guava. I see from the #Override in the code you posted that IShape seems to require a Point[] from the getPoints() method, but I'm ignoring that for the sake of example since the use of object arrays is a rather poor idea, especially if you want immutability (since they cannot be immutable and all).
public final class Triangle implements IShape, Serializable {
private final ImmutableList<Point> points;
public Triangle(Point a, Point b, Point c) {
this.points = ImmutableList.of(a, b, c);
}
public ImmutableList<Point> getPoints() {
return this.points;
}
// ...
}
Point should also be more like:
public final class Point implements Serializable {
/*
* Could use public final here really, but I prefer
* consistent use of methods.
*/
private final int x;
private final int y;
private final int z;
public Point(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
// getters, etc.
}
In order to be an immutable class, it is not enough that your methods promise not to change the object. In addition to having all fields be private and the methods not allow changing, you must also guarantee that the subclasses have the same promise of immutability. This includes making the class itself final, and ensuring that no references to the fields are ever returned.
A short, but excellent treatment of this can be found in this article:
http://www.javaranch.com/journal/2003/04/immutable.htm
Not only do you need to provide an immutable copy of the internalised array, you also need to make sure that the Point object is immutable.
Consider the following use of the Point class in the standard Java API:
Point a = new Point(1,1);
Point b = new Point(1,1);
Point c = new Point(1,1);
Triangle triangle = new Triangle(a, b, c);
System.out.println(Arrays.toString(triangle.getPoints()));
c.setLocation(99,99);
System.out.println(Arrays.toString(triangle.getPoints()));
It is not immutable because ...
Triangle t1 = new Triangle(new Point(0,0), new Point(0, 10), new Point(10, 10));
Triangle t2 = t1;
System.out.println( t1.getPoints()[0] ); // -> 0
t2.getPoints()[0].x = 10;
System.out.println( t1.getPoints()[0] ); // -> 10
Thus the class is not immutable because you can change the state of an instance (internal Point[] exposed) and this also changes the state of a reference to the same instance.
To make it a true immutable class, you would need methods to separately get X and Y from each point, for example:
public int getPointX(int point) { return points[point].x; }
public int getPointY(int point) { return points[point].y; }
or
public Point getPoint(int point) { return new Point(points[point]); }
or return a copy of the points like you suggested in your edit.
In addition to what others have already noted, you should:
Make your Triangle class final to prevent the creation of mutable Triangles by subclasses.
Declare all the fields final, to catch accidental modification of fields by the class itself.
In "Effective Java," Joshua Bloch provides a list of rules for immutable classes in general, in Item 15: Minimize Mutability.
1) Make members private and final - so
private Point[] points; //should be
private final Point[] points;
2) Make class final so it cannot be sub-classed
3) Exclusive access to mutable members (array) - meaning return copy of and not the reference to mutable members
For the best treatment of this subject refer to Joshua Bloch, Effective Java- item 15
This could be a better Point implementation.
import java.io.Serializable;
public final class Point implements Serializable {
private static final long serialVersionUID = 0x100;
private final int x;
private final int y;
private final int z;
public Point(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
public Point(Point that) {
this(that.x, that.y, that.z );
}
public boolean equals(Object obj) {
// assume this is a typical, safe .equals implementation
// that compares the coordinates in this instance to the
// other instance
return true;
}
}
Other than exposing the array (as getters are wont to do) and not being final, being serialisable is "problematic".
As a very nasty man, when deserialising, I can get another reference to the internal array. The obvious fix for this is:
private void readObject(
ObjectInputStream in
) throws ClassNotFoundException, IOException {
ObjectInputStream.GetField fields = in.readFields();
this.points = ((Point[])(fields.get("point", null)).clone();
}
That still leaves the problem of points not being final and exposing the object without points initialised (or worse, but a bit thoeretical, partially initialised). What you really want is a "serial proxy", which you can find out about on the internets...
Note: If you implement equals you should also implement hashCode, probably toString and possible Comparable.
Point itself doesn't have to be immutable for Triangle to be immutable. You just have to do a lot of defensive copies so that nobody has a reference to the Point objects stored in the Triangle.
Also, shouldn't triangle a-b-c equal triange b-c-a (and 4 other permutations)
A immutable class example with mutable field:
public final class ImmutabilityTest {
private final int i;
private final C c1;
ImmutabilityTest(int i, C c1){
this.i = i;
this.c1 = c1;
}
public int getI() {
return i;
}
public C getC1() {
return (C)c1.clone();//If return c1 simply without calling clone then contract of immutable object will break down
}
#Override
public String toString() {
return "ImmutabilityTest [i=" + i + ", c1=" + c1 + "]";
}
public static void main(String[] args) {
ImmutabilityTest i1 = new ImmutabilityTest(10, new C(new D("before")));
System.out.println(i1);
i1.getC1().getD1().name = "changed";
System.out.println(i1);
}
}
class C implements Cloneable{
D d1;
public C(D d1) {
super();
this.d1 = d1;
}
public D getD1() {
return d1;
}
public void setD1(D d1) {
this.d1 = d1;
}
#Override
public String toString() {
return "C [d1=" + d1 + "]";
}
public C clone(){
C c = null;
try {
c = (C) super.clone();
c.setD1(c.getD1().clone());// here deep cloning is handled if it is commented it will become shallow cloning
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return c;
}
}
class D implements Cloneable{
String name;
public D(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public String toString() {
return "D [name=" + name + "]";
}
public D clone(){
D d = null;
try {
d = (D) super.clone();
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return d;
}
}

Categories

Resources