Why is this set containment check failing? - java

I am going through the Effective Java 3rd edition and I was reading Item 10: Follow Equals contract when overriding.
There is an example there which I was trying to simulate on my machine. Below is the code for the same.
public class Point {
private int x;
private int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
#Override
public boolean equals(Object obj) {
if (!(obj instanceof Point))
return false;
Point p = (Point)obj;
return (x == p.x) && (y ==p.y);
}
// Use this for demonstration with AtomicPoint class.
/*#Override
public boolean equals(Object obj) {
if(obj == null || (obj.getClass() != getClass())) {
return false;
}
Point p = (Point)obj;
return p.x == x && p.y == y;
}*/
}
public class AtomicPoint extends Point{
private static final AtomicInteger counter = new AtomicInteger();
public AtomicPoint(int x, int y) {
super(x, y);
counter.incrementAndGet();
}
public static int getCounter() {
return counter.get();
}
private static Set<Point> sampleSet = new HashSet<>();
public static void main(String[] args) {
sampleSet.add(new Point(1,2));
sampleSet.add(new Point(1,3));
sampleSet.add(new Point(1,4));
AtomicPoint ap = new AtomicPoint(1,3);
// This should return true but its returning false
System.out.println(sampleSet.contains(ap));
}
}
As you can see from the comment in the AtomicPoint class, I am getting false for the contains check, whereas Joshua Bloch states that this should return true. Can someone help me here?

For using HashSet<T> or HashMap<T> you need to override hashCode() methods from super class. You should have in your editor automatically generating hashCode() and equals() methods (and i'm suggesting you to use that always in every class). If you want to use TreeSet<T> or TreeMap<T> you will need to implement Comparable or Comparator<T> interface and override their compare() or compareTo() methods for using it.

Related

How can I get more than two answers from a boolean variable?

I need to create a class called Point, this Object will have parameters of X and Y. Then I had to make a method which checks if that point is above another point, so I did that:
public boolean isAbove(Point1 other) {
if(other.getY() > _y) { return true; }
return false;
}
And the next method I had to do called "isUnder", but in this method I must only use the "isAbove" method I've created. This is the "isUnder" method I've created:
public boolean isUnder(Point1 other) {
return !isAbove(other);
}
How can I know if the point aren't at the same "height"? With the methods I created the only results I get are TRUE, FALSE, but if the points are the same "height" I should get FALSE,FALSE on both methods.
class Point {
private double x;
private double y;
public PointYPosition getYPosition(Point otherPoint) {
if (otherPoint.y > y) return PointYPosition.ABOVE;
if (otherPoint.y < y) return PointYPosition.UNDER;
return PointYPosition.EQUALS;
}
}
enum PointYPosition {
ABOVE,
UNDER,
EQUALS
}
You can use the following implementation, however I must say if you need to only use the other method, there is no way
public boolean isUnder(Point1 other) {
return !isAbove(other) && other.getY() != _y;
}
That way you can even have a third method isEqual
public boolean isEqual(Point1 other) {
return !isAbove(other) && !isUnder(other);
}
That being said here is how I would implement this myself
public boolean isAbove(Point1 other) {
return other.getY() < _y;
}
public boolean isUnder(Point1 other) {
return other.getY() > _y;
}
public boolean isOnTheSameHeight(Point1 other) {
return !isAbove(other) && !isUnder(other);
}
public boolean isAboveOrOnTheSameHeight(Point1 other) {
return isAbove(other) || isOnTheSameHeight(other);
}
// etc.
You can do something like this:
public int compareTo(Point otherPoint) {
return Integer.compare(_y, otherPoint.getY());
}
The Integer.compare(x, y) returns -1 if x is less than y, returns 0 if they're equal, and returns 1 otherwise.
Apparently I found a post from 7 years ago with the exact same question, someone solved it there
return other.isAbove(this);
Thank you all very much!

How to get a value in map by point?

I have a point class:
class Point
{
public int x;
public int y;
public Point(int x,int y)
{
this.x=x;
this.y=y;
}
}
And I have a map to store the values:
Map<Point,Integer> map = new HashMap<Point,Integer>();
map.put(new point(1,1)) = 10;
I want to get the values in map by a definite point:
map.get(new point(1,1));
but it returns null.
It may because of the difference of their reference.
I want to know how to fix it,instead of using a two-dimensional array.
when using structures like Map class you should implement the equals and hashCode method so when the get method of Map get called these methods will call respectively
something like this:
class Point {
public int x;
public int y;
public Point(int x,int y)
{
this.x=x;
this.y=y;
}
#Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
Point point = (Point) o;
return x == point.x && y == point.y;
}
#Override
public int hashCode() {
return Objects.hash(x, y);
}
}

Override equals method in java

Let's consider the following simple class.
class Point {
private float x;
private float y;
public Point(float x, float y){
this.x=x;
this.y=y;
}
public float getX(){return this.x;}
public float getY(){return this.y;}
public void setX(float x){this.x=x;}
public void setY(float y){this.y=y;}
#Override
public String toString(){
return ("x = "+this.x+", y = "+this.y+";");
}
#Override
public Point clone(){
return new Point(this.x,this.y);
}
#Override
public boolean equals(Object object){
if (object != null && object.getClass()==Point.class){
return object.getX()==this.x && object.getY()==this.y;
}
else{
return false;
}
}
The problem is in the rewrite of method equals: I use the general Object class as attribute to make it more flexible, but netbeans prints error on return line: "Object has no method getX" which is perfectly logical.
But the problem is still here, how can I manage to fix this?
Thanks you in advance
This is pretty simple but you need to cast object:
#Override
public boolean equals(Object object){
if (object != null && object.getClass()==Point.class){
Point p = (Point)object;
return p.getX()==this.x && p.getY()==this.y;
}
else{
return false;
}
}
This is also relevant: Casting in equals method

Interface and type casting

In the Java 8 tutorial about interface, one example says that when a class implements an interface, one has to type cast the interface type into the class type in order to invoke methods of this class, as shown by the following example from the java 8 tutorial:
public class RectanglePlus
implements Relatable {
public int width = 0;
public int height = 0;
public Point origin;
// four constructors
public RectanglePlus() {
origin = new Point(0, 0);
}
public RectanglePlus(Point p) {
origin = p;
}
public RectanglePlus(int w, int h) {
origin = new Point(0, 0);
width = w;
height = h;
}
public RectanglePlus(Point p, int w, int h) {
origin = p;
width = w;
height = h;
}
// a method for moving the rectangle
public void move(int x, int y) {
origin.x = x;
origin.y = y;
}
// a method for computing
// the area of the rectangle
public int getArea() {
return width * height;
}
// a method required to implement
// the Relatable interface
public int isLargerThan(Relatable other) {
RectanglePlus otherRect
= (RectanglePlus)other;
if (this.getArea() < otherRect.getArea())
return -1;
else if (this.getArea() > otherRect.getArea())
return 1;
else
return 0;
}
}
In the method isLargerThan(Relatable other), other is casted to type RectanglePlus in order to invoke getArea().
In the other example about default methods in interface, the compareTo(Card o) method doesn't type cast o to type PlayingCard, but can invoke int hashCode() directly, I don't understand this. Thanks for your help.
package defaultmethods;
public class PlayingCard implements Card {
private Card.Rank rank;
private Card.Suit suit;
public PlayingCard(Card.Rank rank, Card.Suit suit) {
this.rank = rank;
this.suit = suit;
}
public Card.Suit getSuit() {
return suit;
}
public Card.Rank getRank() {
return rank;
}
public boolean equals(Object obj) {
if (obj instanceof Card) {
if (((Card)obj).getRank() == this.rank &&
((Card)obj).getSuit() == this.suit) {
return true;
} else {
return false;
}
} else {
return false;
}
}
public int hashCode() {
return ((suit.value()-1)*13)+rank.value();
}
public int compareTo(Card o) {
return this.hashCode() - o.hashCode();
}
public String toString() {
return this.rank.text() + " of " + this.suit.text();
}
public static void main(String... args) {
new PlayingCard(Rank.ACE, Suit.DIAMONDS);
new PlayingCard(Rank.KING, Suit.SPADES);
}
}
In short: Because hashCode is defined in java.lang.Object and every other class extends Object implicitly.
So when you have
public int compareTo(Card o) {
return this.hashCode() - o.hashCode();
}
the compiler already knows that o is of type Card which extends Object which defines a hashCode method. No need for an explicit cast.
On the other hand in your isLargerThan method the parameter is of type Relatable:
public int isLargerThan(Relatable other) {
RectanglePlus otherRect
= (RectanglePlus)other;
if (this.getArea() < otherRect.getArea())
return -1;
else if (this.getArea() > otherRect.getArea())
return 1;
else
return 0;
}
And judging from the link you provided, the getArea method is defined in RectanglePlus only. Since the compiler only sees Relatable it does not know anything about a getArea method at this point and you need to explicitly cast other to RectanglePlus to be able to access it.
Note that you should actually do an instanceof check before casting to avoid a ClassCastException when other is not a RectanglePlus (you don't know if there might be other classes implementing Relatable).
Let me try a non-code related example:
If people have a pet they usually give it a name. So whatever pet you have, one can always ask for its name (cf. hashCode). But they cannot ask you to make it bark (cf. getArea) unless they know that it is a dog.
And you will probably fail to make a cat bark (cf. ClassCastException).

Ap Computer Science Java Interfaces and Compare method dilemma

I'm supposed to write a Cruiser class which implements the Locatable interface. Cruiser will have x, y, and speed properties. x, y, and speed are integer numbers. You must provide 3 constructors for class Cruiser. Class Cruiser must implement the Locatable interface.
One constructor must be a default. One constructor must be an x and y only constructor. One constructor must be an x, y, and speed constructor. You must provide an equals method. The equals() method should compare the properties of two Cruiser Objects. You must provide a toString() method. The toString() should return the x, y, and speed of the Cruiser.
When i compile this it says "class Cruiser is public, should be declared in Cruiser.java"
When i do this my IDE says ";" as expected after public boolean equals. but that doesn't make sense why you would need a semicolon in a method.
this is what i have so far
public interface Locatable
{
public int getxPos();
public int getyPos();
}
public class Cruiser implements Locatable
{
private int xPos, yPos, speed;
public Cruiser()
{
xPos=yPos=speed=0;
}
public Cruiser(int x,int y)
{
xPos=x;
yPos=y;
speed=0;
}
public Cruiser(int x, int y, int spd)
{
xPos=x;
yPos=y;
speed=spd;
}
public int getxPos()
{
return xPos;
}
public int getyPos()
{
return yPos;
}
public int getSpeed()
{
return speed;
}
public void compare(Cruiser A, Cruiser B)
{
#Override
public boolean equals(Object obj)
{
if (obj instanceof Cruiser) {
Cruiser cruiserToCompareTo = (Cruiser)obj;
if(xPos == cruiserToCompareTo.getXpos() &&
yPos == cruiserToCompareTo.getYpos() &&
speed == cruiserToCompareTo.getSpeed())
return true;
}
return false;
}
public String toString()
{
String properties = "X position:"+ xPos+ ", Y position:"+yPos+ ",Speed:"+speed;
return properties;
}
}
}
Here is what it means that equals should compare the fields/properties.
public boolean equals(Object obj) {
if (obj instanceof Point) {
Point pt = (Point)obj;
return (x == pt.x) && (y == pt.y);
}
return super.equals(obj);
}
This example is taken from java.awt.Point
which is one of the Java's built-in classes.
So Point has 2 properties x and y, and
in its equals method it is comparing them.
See also:
java.awt.Point.equals
You have a Cruiser A with properties x,y,speed and you have Cruiser B with x,y,speed. Equals shall return true, if A.x == B.x, A.y == B.y, A.speed == B.speed all are true. Cruiser A and Cruiser B are therefor equal, when all parameters are equal.
Edit: Following Code should be entered into Cruiser-Class
public int getSpeed() {
return speed;
}
#Override
public boolean equals(Object obj) {
if (obj instanceof Cruiser) {
Cruiser cruiserToCompareTo = (Cruiser)obj;
if(xPos == cruiserToCompareTo.getXpos() &&
yPos == cruiserToCompareTo.getYpos() &&
speed == cruiserToCompareTo.getSpeed())
return true;
}
return false;
}
And please: Format you code better and furthermore name methods in Cruiser-Class same way as in the interface.
Edit 2: Regarding your second problem:
You need to have to separate files, Cruiser.java and Locatable.java. Code runs well here

Categories