I have an abstract class called DrawingObject that is extended by four subclasses: Point, Line, FreeFormLine, and Circle. DrawingObject implements Comparable and I have defined the compareTo method to look like this
public int compareTo(DrawingObject object)
{
if(object instanceof Point && this instanceof Point)
{
//determine which has a higher value
return 0;
}
else if(object instanceof Point && this instanceof Line)
return 1;
else if(object instanceof Point && this instanceof FreeFormLine)
return 1;
else if(object instanceof Point && this instanceof Circle)
return 1;
else if(object instanceof Line && this instanceof Point)
return -1;
else if(object instanceof Line && this instanceof Line)
{
//determine which has a higher value
return 0;
}
else if(object instanceof Line && this instanceof FreeFormLine)
return 1;
else if(object instanceof Line && this instanceof Circle)
return 1;
else if(object instanceof FreeFormLine && this instanceof Point)
return -1;
else if(object instanceof FreeFormLine && this instanceof Line)
return -1;
else if(object instanceof FreeFormLine && this instanceof FreeFormLine)
{
//determine which has a higher value
return 0;
}
else if(object instanceof FreeFormLine && this instanceof Circle)
return 1;
else if(object instanceof Circle && this instanceof Point)
return -1;
else if(object instanceof Circle && this instanceof Line)
return -1;
else if(object instanceof Circle && this instanceof FreeFormLine)
return -1;
else if(object instanceof Circle && this instanceof Circle)
{
//determine which has a higher value
return 0;
}
return 0;
}
Now that I have this I would like to extend the code the sorting by value. I am confused as how to go about doing this. For example Point has two instance fields, double x and double y. I am confused as to which to sort by. I am also in confusion over the other types of objects and how to sort them. Each class has an equals method that is declared abstract in DrawingObject but implemented in each subclass.
Here are description of the fields in each class:
Point has two double fields, x and y. These represent the coordinates on a Cartesian coordinate grid of the point.
Line has two Point fields, p1 and p2. These represent the start and end points of the line.
FreeFormLine has one ArrayList field, points. This represents all of the points along the line.
Circle has one Point field, center, and one double field, radius. These represent the center point of and radius of the circle.
In conclusion, how do I determine which object has more or less value when there is more than one field to evaluate?
Edit:
The purpose of doing this sorting is allow me to search efficiently through an array of DrawingObjects using binary seaching.
The problem that you are trying to solve is much harder than ut seems, because you are trying to build a double dispatch method, i.e. a method that is virtual with respect to two objects.
There are ways to do that, for example, using a visitor pattern, but if you would be fine with establishing a fixed order across different classes (say, a point is always less than a rectangle, a rectangle is less than a line, etc.) you could make your code very consistent by making a protected method in your base class that returns the "sort order" for the class:
protected abstract int sortOrder();
Point would return 0, rectangle would return 1, line would return 2, and so on. Now your comparison method could call sortOrder() on both sides, and decide which one is less than the other if sort ordrrs are not the same.
If sort orders are the same, then the classes are the same. Implement comparable in each class, and forward the call to class-specific comparison method when classes are the same.
As far as comparison of the same class goes, you can decide on an arbitrary ordering among the attributes - say, x before y, height before width, etc. As long as you are consistent about applying your rules, your ordering is going to be fine.
Related
Currently I have a method overloading the following method:
public boolean isHorizontalOrVertical(Point firstPoint, Point secondPoint) {
return firstPoint.getFirstComponent() == secondPoint.getFirstComponent()
|| firstPoint.getSecondComponent() == secondPoint.getSecondComponent();
}
public boolean isHorizontalOrVertical(List<Point> points) {
if (points == null || points.size() < 2) {
throw new IllegalArgumentException("invalid number of points");
}
Point start = points.get(0);
return points.stream()
.allMatch(p -> isHorizontalOrVertical(start, p));
}
The method is needed to check if two or three points are vertical/horizontal to each other. In the case of three points, it just has to check if the two last points are horizontal/vertical to the start point.
Does anyone have any idea how I can get it all into just one method?
First and foremost I have to note the fact that it doesn't make sense, to me at least, a method which calculates if two entities are horizontal or vertical and those entities are Points. How can two points be horizontal or vertical?
isHorizontalOrVertical is a bad name
Overcoming the above, you could create a single method which calculates if two points are horizontal or vertical.
Change the name isHorizontalOrVertical because it's redundant. A better name is isHorizontal or isVertical. The method will return a boolean so if isHorizontal returns false, then it's vertical and vice versa. Probably a better name could be areTwoPointsHorizontal but I am having trouble even writing that because it transmits the wrong message, but feel free to choose your own.
So the method,
public boolean isHorizontal(Point first, Point second){
boolean sameFirstComponents = firstPoint.getFirstComponent() ==
secondPoint.getFirstComponent();
boolean sameSecondComponents = firstPoint.getSecondComponent() ==
secondPoint.getSecondComponent();
return sameFirstComponents || sameSecondComponents;
}
Finally, create a method which calculates if an arbitary number of points in a list are all between them horizontal or vertical (assuming if point A is horizontal with point B, then if point C is horizontal with B, so is with A).
Oveload that method since it does the same thing and the only thing changing are the parameters. (Note the use of the simple isHorizontal method from above)
public boolean isHorizontal(List<Point> points){
boolean allPointsHorizontal = true;
for (int i=0; i<points.size(); i++) {
boolean nextPointExists = i<points.size() - 1;
if (nextPointExists) {
Point current = points.get(i);
Point next = points.get(i+1);
allPointsHorizontal = allPointsHorizontal && isHorizontal(current,next);
if (!allPointsHorizontal)
return false;
}
}
return allPointsHorizontal;
}
You can have just one method as follows:
public boolean isHorizontalOrVertical(List<Point> points) {
if (points == null || points.size() < 2) {
throw new IllegalArgumentException("invalid number of points");
}
if (points.size() == 2) {
return points.get(0).getFirstComponent() == points.get(1).getFirstComponent()
|| points.get(0).getSecondComponent() == points.get(1).getSecondComponent();
}
Point start = points.get(0);
return points.stream()
.allMatch(p -> isHorizontalOrVertical(List.of(start, p)));
}
Note: If you are not using Java version >= 9, please use Arrays.asList instead of List.of.
The method could be implemented like this:
public boolean isHorizontalOrVertical(Point firstPoint, Point secondPoint, Point thirdPoint) {
return isHorizontalOrVertical(Arrays.asList(firstPoint, secondPoint, thirdPoint));
}
Your isHorizontalOrVertical(List<Point>) method will fail when the list is empty, and the call doesn't make much sense when the list has only one element.
I think a better way to do this is with two required parameters, plus a variadic parameter, so that callers must at least give 2 points.
private boolean are2PointsHorizontalOrVertical(Point firstPoint, Point secondPoint) {
return firstPoint.getFirstComponent() == secondPoint.getFirstComponent()
|| firstPoint.getSecondComponent() == secondPoint.getSecondComponent();
}
public boolean arePointsHorizontalOrVertical(Point point1, Point point2, Point... rest) {
return are2PointsHorizontalOrVertical(point1, point2) &&
Arrays.stream(rest).allMatch(x -> are2PointsHorizontalOrVertical(point1, x));
}
This technically is still "one method" as far as the public interface is concerned. You can substitute the helper are2PointsHorizontalOrVertical back into the public method if you really want, but I don't see any benefit in doing that.
Actually, you can have only one method:
public boolean isHorizontalOrVertical(Point firstPoint, Point secondPoint, Point... others) {
// check firstPoint, secondPoint for null is ommited
if (others == null || others.length == 0) {
return firstPoint.getFirstComponent() == secondPoint.getFirstComponent()
|| firstPoint.getSecondComponent() == secondPoint.getSecondComponent();
} else {
// First, create a stream with second point + others elements
// then match against the first point
return Stream.of(new Point[]{secondPoint}, others).flatMap(e -> Stream.of(e))
.allMatch(p -> isHorizontalOrVertical(firstPoint, p));
}
}
So, I'm making a fullscreen application and ran across something weird.
The Method DisplayMode.equals(DisplayMode dm) is overridden but I don't think it's implemented quite right. The following code prints false to the console:
public static void main(String[] args){
DisplayMode mode = new (1,2,16, DisplayMode.REFRESH_RATE_UNKNOWN);
System.out.println(mode.equals(new DisplayMode(1, 2, 16, 60)));
}
If the display modes are the same save for their refresh rates, and one of them is unknown, then I think they should be equal. Why is that not the case, and can someone suggest a workaround for me to use? Also, why do the online the Java Docs show that there are two overloaded versions of the .equals() method, one with a DisplayMode Object and one with a Java.Lang.Object Object? https://docs.oracle.com/javase/7/docs/api/java/awt/DisplayMode.html
The difference I believe is that in the first case, you're saying "I know for a fact that the refresh rate is unknown" and in the second case you're saying "I know for a fact that the refresh rate is 60".
The implementation from grepcode shows the following:
public boolean equals(DisplayMode dm) {
if (dm == null) {
return false;
}
return (getHeight() == dm.getHeight()
&& getWidth() == dm.getWidth()
&& getBitDepth() == dm.getBitDepth()
&& getRefreshRate() == dm.getRefreshRate());
}
you can see that it compares the value of the refresh rate at the bottom.
java.awt.DisplayMode#REFRESH_RATE_UNKNOWN is defined as 0.
As for the second question, about why that overload the equals method, it allows the code to separated and focus on only the part it cares about. For example, if it were not overloaded, the equals method would look like
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (obj instanceof DisplayMode) {
DisplayMode dm = (DisplayMode) obj;
return (getHeight() == dm.getHeight()
&& getWidth() == dm.getWidth()
&& getBitDepth() == dm.getBitDepth()
&& getRefreshRate() == dm.getRefreshRate());
}
return false;
}
This equals() method will produce the same output if lines 3-5 are omitted (I numbered these lines). What is the point of these lines?
/** Return true if that Beetle has the same parts as this one. */
public boolean equals(Object that) {
3. if (this == that) {
4. return true;
5. }
if (that == null) {
return false;
}
if (getClass() != that.getClass()) {
return false;
}
Beetle thatBeetle = (Beetle) that;
return body == thatBeetle.body
&& eyes == thatBeetle.eyes
&& feelers == thatBeetle.feelers
&& head == thatBeetle.head
&& legs == thatBeetle.legs
&& tail == thatBeetle.tail;
}
Checking == reference equality is fast, and if true the object is being compared to itself -- so is by definition equal.
This is often used a first step when comparing objects, as it's much faster than comparing all the details. But it's more commonly used from the caller/client function, rather than inside the equals() implementation.
For example, in a linear search:
public int indexOfBeetle (Beetle beetle, List<Beetle> list) {
for (int i = 0; i < list.size(); i++) {
Beetle cand = list.get( i);
if (cand == beetle || cand.equals( beetle))
return i; // Found.
}
// Not Found.
return -1;
}
The operator == checks if the objects are the same instance in memory whereas when you override equals you usually want to perform a logical test.
Let's take an example:
public class Person {
private String name;
// Here there are constructor and getters and setters
}
Now let's run these lines:
Person a = new Person();
Person b = a;
Person c = new Person();
If you compare these instances with == this is what you'll get:
a == a ==> true
a == b ==> true
a == c ==> false
Now, let's set the name:
a.setName("Joe"); // This also sets b because they're the same object
c.setName("Joe");
If our equals looks like this:
public boolean equals (Object other) {
if(other == this) return true;
if(other instanceof Person == false) return false;
if(this.getName().equals(((Person) other).getName())) return true;
}
So we'll now get that a.equals(c) is true even though a==c is false.
So, why do we have the first line? - Some objects' equality is more expensive to compute and by checking this condition at the beginning you might spare some unnecessary computations
Doing that are you checking if the two objects are pointing to the same memory address. Using .equals without it you will achieve the same result because if they are pointing to the same memory address, it's obviously they are equals. But doing that it's much more faster, that's why most developers put this lines on .equals
List<Pair<String, String> > lp = new ArrayList<Pair<String, String> >();
lp.add(new Pair("1", "2"));
How should I check if the list lp contains 1 and 2 i.e the Pair ("1", "2").
Your Pair class needs to implement equals() and hashCode() and you're all set. List.contains() is implemented in terms of the type's equals() method. See the API for List.contains(). (Edited a bit to address comments from #maaartinus, whose answer you should read b/c the observations are solid, and it's a bit ridiculous for me to fold them in here. As maaartinus points out, a best-practice here would be to avoid error-prone manual definitions for equals and hashcode, and instead build on Guava's helper functions for nullable equals and hashCode for n objects).
final class Pair<T> {
final T left;
final T right;
public Pair(T left, T right)
{
if (left == null || right == null) {
throw new IllegalArgumentException("left and right must be non-null!");
}
this.left = left;
this.right = right;
}
public boolean equals(Object o)
{
// see #maaartinus answer
if (! (o instanceof Pair)) { return false; }
Pair p = (Pair)o;
return left.equals(p.left) && right.equals(p.right);
}
public int hashCode()
{
return 7 * left.hashCode() + 13 * right.hashCode();
}
}
With suitable equals(), you can now do:
lp.add(new Pair("1", "2"));
assert lp.contains(new Pair("1","2"));
Responding to the comments below, perhaps it would be good to include a good reference for "Why do I need to implement hashCode()?"
JavaPractices.com — Implementing equals() — "if you override equals, you must override hashCode"
Object.equals() contract as defined in the API documentation
StackOverflow answer
The implementation in the answer by andersoj
return left != null && right != null && left.equals(p.left) && right.equals(p.right);
is wrong: The null tests clearly suggest that null is a legal value for left and right. So there are at least two problems there:
new Pair(null, null).hashCode() throws NPE
new Pair(null, null) does NOT equal to itself!
Have a look at Guava class Objects for a correct implementation. Use it or write a static helper methods like
public static boolean equal(Object a, Object b) {
return a==b || a!=null && a.equals(b);
}
public static int hashCode(Object a) {
return a==null ? 0 : a.hashCode();
}
and always use them.
Never ever write equals containing a null test.
It's to easy to blow it, and nobody noticed it. Using the Helper, it's trivial to get it right:
public boolean equals(Object o) {
if (!(o instanceof Pair)) return false;
Pair p = (Pair) o;
return Helper.equals(left, p.left) && Helper.equals(right, p.right);
}
public int hashCode() {
return 7 * Helper.hashCode(left) + 13 * Helper.hashCode(right);
}
Of course, forbidding nulls in the constructor is an option, too.
I defined this simple method:
public static boolean isBorder(int x, int y) throws CollisionDetectionException {
try {
if ( (levelItems[x][y] instanceof StaticGameObject && levelItems[x][y].isVisible()) ||
(levelItems[x-1][y] instanceof StaticGameObject && levelItems[x-1][y].isVisible()) ||
(levelItems[x][y+1] instanceof StaticGameObject && levelItems[x][y+1].isVisible()) ||
(levelItems[x][y-1] instanceof StaticGameObject && levelItems[x][y-1].isVisible()) ||
(levelItems[x-1][y-1] instanceof StaticGameObject && levelItems[x-1][y-1].isVisible()) ||
(levelItems[x-1][y+1] instanceof StaticGameObject &&levelItems[x-1][y+1].isVisible()) ||
(levelItems[x+1][y] instanceof StaticGameObject && levelItems[x+1][y].isVisible()) ||
(levelItems[x+1][y+1] instanceof StaticGameObject && levelItems[x+1][y+1].isVisible()) ||
(levelItems[x+1][y-1] instanceof StaticGameObject && levelItems[x+1][y-1].isVisible()) ) {
return true;
} else {
return false;
}
} catch (ArrayIndexOutOfBoundsException e) {
throw new CollisionDetectionException("Collision couldn't be checked because checking position " + x + "/" + y + " caluclated values below (0/0)");
}
}
As you can see i have a 2dimensional array. Now i want to check a specific position ((x/y) -> the method arguments), if there are any visible StaticGameObject in the neighbouring fields of the 2dimensional array.
The levelItems array consists of so called GameObject. StaticGameObject is a a direct subclass of GameObject.
Any hints how to improve this method?
Add a method to GameObject
bool isBorderObject() { return false; }
Then override in StaticGameObject
bool isBorderObject() { return true; }
change the test to
(levelItems[x][y].isBorderObject() && levelItems[x][y].isVisible())
Also, the if could be this nested for
for (int i = x-1; i <= x+1; ++i) {
for (int j = y-1; j <= y+1; ++j) {
GameObject item = levelItems[i][j];
if (item.isBorderObject() && item.isVisible())
return true;
}
}
return false;
(Disclaimer: I've worked on Java games running on a lot of mobile devices)
People already showed how to simplify all these if statements. I'd add that defining your own CollisionDetectionException is probably completely overkill.
For a start, such low-level Java details don't exist at the OO level: exceptions, especially checked exceptions, are a Java idiosynchrasies that is really not necessary. Some very good and very impressive Java frameworks do mostly away with them, like Spring. Then a lot of very impressive and powerful apps, made of millions and millions of lines of code, run perfectly fine without ever using the concept of checked exception because they're, well, written in language in that don't have this kind of concept (once again: a "checked exception" doesn't exist at the OO level, hence any OOA/OOD to OOP without ever needing to use checked exception).
In any case: there's really no reason to turn an ArrayIndexOutOfBoundException into your own specific checked exception. This means you plan to use exception for flow control, which is a HUGE no-no.
Then, regarding your "isBorder" test... You probably don't need that. You think you do, but you really don't. Why do you want to know if it's a "border"? To detect a collision I guess.
You're using a static method to detect if it's a border, and static is the anti-thesis of OO. What is important is the messages you are passing around between objects. You may have all your objects responding to some isCollidingWith(...) message: objects that are "border" knows they are border, they'll know how to deal with a isCollidingWith(...) message.
Then you can go even further: instead of doing a isCollidingWith(...) you could have some resolveCollisionWith(...) method.
public class Wall implements MySuperAbstraction {
int wallHitPoints = 42;
boolean isWallStillUp = true;
void resolveCollisionWith( SomeObject o ) {
if ( o.isStrongEnoughToHarmWall ) {
wallHitPoints--;
isWallStillUp = wallHitPoints > 0;
}
}
}
This is just a quick piece of code and it doesn't deal with the fact that SomeObject needs probably to bounce when he hits the wall, etc. but the point stands: in OO objects knows how to communicate between themselves. They know how to deal with the various messages passed around.
If you want to do OO, then all I can tell you is that Java's static, instanceof and checked exceptions are definitely not the way the go. Basically, they're the anti-thesis of OO :)
]
This should get rid of the extremely large if block you have:
for(int col = x-1; col <= x+1; col++)
{
for(int row = y-1; row <= y+1; row++)
{
if(levelItems[row][col] instanceof StaticGameObject && levelItems[row][col].isVisible())
return true;
}
}
(This solution merely reduces the crazy if, not get rid of the instanceof, as you can see)
Of course, in both my example and yours, you should make sure to check for array bounds problems.
A revision to #Lou's solution which is to have one method and one loop.
for (int i = 0; i < 9; i++)
if (levelItems[x-1 + i/3][y-1 + i%3].isBorderObjectVisible())
return true;
return false;
Think about "inversion of control".
As an example, how could introducing this method to the GameObject class:
public boolean
isBorder()
{
return false;
}
and this override in the StaticGameObject class:
public boolean
isBorder()
{
return self.isVisible();
}
simplify the code above?
Another nice technique is to have a function that returns the set of adjacent cells. In this way you avoid (or anyway move) the double-loop. It's better separation of concerns; when you discover that your algorithm was forgetting about out-of-bounds conditions, there's exactly one place to fix it.
public Set<GameObject> adjacentItems(int x, int y) {
Set<GameObject> set = new HashSet<GameObject>();
for (int i = -1; i < 2; ++i)
for (int j = -1; j < 2; ++j)
set.add(levelItems[x+i][y+j]);
return set;
}
public boolean isBorder(int x, int y) {
for (GameObject item : adjacentItems(x, y))
if (item.isBorder() && item.isVisible())
return true;
return false;
}
Don't make this any more complex. Simply be sure all subclasses of GameObject implement isVisible. That's all it takes.
If you need to also distinguish moveable vs. non-movable, then you need two methods:
isVisible -- visible or not
isMovable -- moveable or not
You never need instanceof.
[It's not clear from the question, but it appears that the class StaticGameObject actually means is a subclass of GameObject with isMovable() false.]