== vs equals method for Doubles [duplicate] - java

This question already has answers here:
Why can't we use '==' to compare two float or double numbers [duplicate]
(3 answers)
Closed 6 years ago.
I have this class
public class Point {
private Double[] coordinates;
private int dimension;
public Point(Double[] coordinates) {
dimension = coordinates.length;
this.coordinates = new Double[dimension];
for(int i = 0; i < dimension; i++)
this.coordinates[i] = coordinates[i];
}
public Double getCoord(int n) {
if(n < 0 || n > dimension -1 ){
throw new RuntimeException("error de coordenadas");
}
return coordinates[n];
}
public int getDim() {
return dimension;
}
public boolean equals(Object p1){
if( (p1 instanceof Point) ){
Point p = (Point) p1;
int n = p.getDim();
if(getDim() == n)
{
for(; n > 0; n--)
{
if( Double.valueOf(this.getCoord(n-1)) != Double.valueOf(p.getCoord(n-1)) ) // <------- BAD LINE!
{
System.out.println("Checking coord " + (n-1));
System.out.println("Coord " + (n-1) + " p = " + Double.valueOf(this.getCoord(n-1)));
System.out.println("Coord " + (n-1) + " p2 = " + Double.valueOf(p.getCoord(n-1)));
return false;
}
}
}
return true;
}
return false;
}
}
And this main
public class FigureTest {
public static void main(String[] args){
Double[] coord1 = {2.0,3.3};
Double[] coord2 = {2.0,3.3};
Point p = new Point(coord1);
Point q = new Point(coord2);
System.out.println(p.equals(q));
}
}
I can't understand why this p.equals(q) returns false! It goes inside the if( Double.valueOf(... but then prints that both coordinates are equal. It's the same if I remove the Double.valueOf. The only way it worked was when I put ! if(this.getCoord(n-1).equal(p.getCoord(n-1)), but I don't understand why the others don't work.

Double.valueOf returns a Double object, not a primitive double.
You perform a reference check (!=). So even if Double.valueOf(getCoords(n-1)) returned the same numeric value for both calls, different objects would be wrapping the numbers, so the != check would be true, causing your equals to return false.
Here's a quick example:
public static void main(String[] args){
System.out.println(Double.valueOf(5) == Double.valueOf(5));
}
Notice how it returns false. That's because == is a reference check, and a different object is being returned each time you call Double.valueOf. So when you do
Double.valueOf(...) != Double.valueOf(...)
That check will return true, since the valueOf calls didn't return the same object. This is why the check in your code returns true, resulting in equals returning false.
To fix this, you could...
Change your != check into a .equals check, which will compare the numeric values rather than the references.
Double.valueOf(...).equals(Double.valueOf(...));
This returns true if both share the same numeric value.
Or you could use doubleValue() when you call getCoord:
getCoord(n-1).doubleValue() != other.getCoord(n-1).doubleValue()
This will avoid the excess creation of Double objects.

In order to this to work;:
p.equals(q)
you need to keep the contract between Hashcode and equals and override properly both of them: equals AND hashcode in the class Point, and when I write properly I mean specifically this:
Please refer to this question if you dont know why or that you dont need it
Double.valueOf(this.getCoord(n-1)) != Double.valueOf(p.getCoord(n-1))
if the members of the class Point are doubles, then you are right when you compare those doubles as criteria to decide if p1.equals(p2)
but according to the documentation of the class Double, the static method Double.compare(this.getCoord(n-1)),p.getCoord(n-1) must be use in order to compare 2 doubles content.
hence I recommend to do in the equals method some similar to this
if( Double.compare(this.getCoord(n-1)),p.getCoord(n-1)!=0) )

Related

Unable to print out b.toString and c.toString

The program's purpose was to teach me how to create a character list, and practice using toString and booleanequals(object other).
public class CharList {
private char[] Array = new char[100];
private int numElements = 0;
public CharList() {
}
public CharList(String startStr){
Array=startStr.toCharArray();
}
public CharList(CharList other){
other.Array=new char[100];
}
public void add(char next) {
Array[numElements++] = next;
}
public char get(int index) {
return Array[index];
}
private int size() {
return numElements;
}
#Override
public String toString() {
String str = new String(Array);
return str;
}
public boolean equals(Object other) {
if(other == null) {
return false;
}
if(other instanceof CharList == false) {
return false;
}
else {
CharList that = (CharList) other;
return this.Array == that.Array ;
}
}
public static void main(String[] args) {
System.out.println("uncomment the code to use the charListDriver");
CharList a = new CharList();
CharList b = new CharList("Batman");
CharList c = new CharList(b);
a.add('k');
a.add('a');
a.add('t');
a.add('n');
a.add('i');
a.add('s');
System.out.println("a is :"+a.toString() +" and has " + a.size() + " chars");
System.out.println("b is :"+b.toString() +" and has " + b.size() + " chars");
System.out.println("c is :"+c.toString() +" and has " + c.size() + " chars")
System.out.println("B and A are equal : " + b.equals(a));
System.out.println("B and C are equal : " + b.equals(c));
}
}
my output is:
a is: katnis and has 6 chars
b is: and has 0 chars
c is: and has 0 chars
The main function was provided for me by my instructor. I don't understand why it is not printing out "batman".
The issue is with your constructor that takes a CharList
public CharList(CharList other){
other.Array=new char[100];
}
You see that it is setting other.Array equal to a new array of size 100.
So when you do this
CharList c = new CharList(b);
You are setting the Array of b to be a new array wiping out the array that contained the characters from "Batman".
If you fix the constructor in question to be
Array = other.Array.clone()
it'll fix the problem. I cloned the other array so that b and c aren't pointing to the exact same array. If they were then when you added chars to one, it would add chars to the other as well.
Next you'll see an issue with your size() method. It returns numElements but numElements isn't set in your constructors that take a String or a CharList so it's always 0. So be sure to set numElements in those constructors. You'll see that because of this error that when you call add on a CharList that was initialized form a String it changes the first char instead of adding it to the end.
I've only really answered the question about Batman and then size. But there are several other issues with this code as well.
What happens if someone calls add more than 100 times on a CharList initialized with default constructor
equals method is doing a reference equality check rather than making sure the chars in the arrays are identical
What happens when you call add to a CharList instantiated with String or CharList? As I noted it currently changes the char at index 0. But even if you fix that and set numElements correctly what will happen? It'll try to write past the end of the Array.
2 Things to go over (plus a 0th thing):
0)
You need to have a getArray() function. Because Array is marked private, there is no way to access it from the outside. You can write other.Array, but because Array is private, it is better practice to use a getArray function. Adding a getArray() is the way to go. (it would be simple, and look like: getArray() {return this.Array;})
1)
Your constructors that you wrote that looks like:
public CharList() {
}
public CharList(CharList other){
other.Array=new char[100];
}
is wrong.
You should change these like so:
public CharList() {
this.Array=new char[100];
}
public CharList(CharList other){
this.Array=other.Array;
}
Here, we made the empty constructor initialize to a set char length of 100. For the other, we made it so that this.Array = other.Array by using other.getArray().
Now, if you try this, it should work.
2)
Lets say you had this:
CharList batman1 = new CharList("batman");
CharList batman2 = new CharList("batman");
Then, java batman1.equals(batman2) would return false. This is because of pointers in java, and the way variable assignment works. for batman1.Array to equal batman2.array, it is not enough for their values to be equal. They also have to have to be pointing to the same thing. See Shallow copy for arrays, why can't simply do newArr = oldArr? for more info.
To fix this, we need a getArray(). Assuming we have it:
public boolean equals(Object other) {
if(other == null) {
return false;
}
if(!(other instanceof CharList)) {
return false;
}
if(other.size()!=this.size()) {
return false;
}
CharList that = (CharList) other;
for (int i=0; i<other.size(); i++) {
if (that.get(i)!=other.get(i)) return false;
}
return true;
}
I did a lot of things here. First, we cleaned up the if statements. You don't need that else at the end. Then, I implemented what is known as a shallow check. It checks if the two Arrays have the same values. If everything is the same, then return true.
If you have followed all of these steps, then it should work.

equals() method not working

The equals() method should check if the dimensions of the first box and the cube are the same. How to fix it? It currently does not work.
The program returns the message "illegal start of type" at if. I am new to this plz help
public class testNew
{
public static void main (String []args)
{
Rectangle3 one = new Rectangle3(5,20);
Box3 two = new Box3(4,4,4);
Box3 three = new Box3(4,10,5);
Cube3 four = new Cube3(4,4,4);
showEffectBoth(one);
showEffectBoth(two);
showEffectBoth(three);
showEffectBoth(four);
}
public static String showEffectBoth(Rectangle3 r)
{
return System.out.println(r);
}
boolean b = two.equals(four);
if (b == true)
{
System.out.println("Box and cube have the same dimensions");
}
}
public class Rectangle3
{
// instance variables
int length;
int width;
public Rectangle3(int l, int w)
{
length = l;
width = w;
}
public int getLength()
{
return length;
}
public int getWidth()
{
return width;
}
public String toString()
{
return getClass().getName() + " - " + length + " X " + width;
}
public boolean equals(Rectangle3 obj)
{
if ((getLength().equals(obj.getLength()) && getWidth().equals(obj.getWidth())))
return true;
else
return false;
}
}
First, regarding the compiler error you have, it has nothing to do with the equals() method. It's only because all of the code below, should be inside your main method as it's the only part where you are declaring the variablestwo and four:
boolean b = two.equals(four);
if (b == true) {
System.out.println("Box and cube have the same dimensions");
}
Notice also, that the Rectangle3 class shouldn't be in the same file as testNew as both are declared public, if you want to use both of them in the same file then you need to remove the public declration from one of them (the one you will not use as filename)
Second, your equals() method is technically correct (I guess functionally as well) but it's not the equals() method you included in your code here, because this one belong to Rectangle3 while the equals() you are testing here should be defined in Box3 and Cube3
NB: Please notice as per assylias's comment, that because b is a boolean there is no need to use if (b == true), just if (b) will be sufficient
It is not the equals function. The line
boolean b = two.equals(four)
Is illegal. It is not within any method and it references variables declared in main()!

Defining a comparator for a quadratic function object

This is my assignment,
a) Write a quadraticFunction that represents a quadratic ax^2 + bx + c with int coeffients a, b, c. Provide a constructor with 3 int parameters for a, b, c. Provide a method double valueAt(double x) returns the value of this quadratic function at x. Also provide a toString method.
b) override the equals method quadraticmethod class. two quadraticfunction should be considered equal if their respective coeffiecients are equal
c) Make the function objects comparable. The compareTo should first compare 1 if equal compare b if equal compare c
d) Define a comparator class for comparing two QuadraticFunction objects. Provide two constructors: a no-argss constructor and a constructor that takes 1 double parameter. When a comparator is created by the no-args constructor, it should compare two quadraticFunction based on their values at x = 0; when a comparator is created by the constructor with a parameter x, it should compare quadraticFunction based on their values at x
Here's my code
I need help with part D, I don't know how to do some of it
public class Ex4
{
int a;
int b;
int c;
public Ex4(int x, int y, int z)
{
a = x; b=y; c=z;
}
public String toString()
{
String X="";
X= X+a+"x^2"+b+"x"+ "+" + c;
return X;
}
public double valueAt(double x)
{
return (a*x*x+b*x+c);
}
//////// Part B
public boolean equals( Ex4 qf )
{
return(this.a==qf.a && this.b==qf.b && this.c==qf.c);
}
/////Part c
// public int compareTo(Ex4 other)
// {
// if (a.equals(other.a))
// {
// if (b.equals(other.b))
// return c.compareTo(other.c);
// return b.comapreTo(other.b);
// }
// return a.compareTo(other.a);
// }
public int compareTo(Ex4 other)
{
if (a > other.a)
return 1;
else if (a < other.a)
return -1;
else if (b > other.b)
return 1;
else if (b < other.b)
return -1;
else if (c > other.c)
return 1;
else if (c < other.c)
return -1;
else
return 0;
}
////Part d
public static void main(String[] args)
{
System.out.println(new Ex3(1, -5, 6));
}
}
Also in the uncomment the area of code under part c, it says int cannot be dereferenced on line 29, 31, 32,33, and 35
Thanks for the help
You can't call methods on primitives, plain and simple.
A better option is to use Integer's static method, Integer.compare(int a, int b) to compare two ints.
First, writing a custom Comparator isn't too terribly difficult; you need to understand the basic structure of one.
Here's the idea: it reads kind of like you're writing a Comparable entity.
class CustomComparator implements Comparator<Ex4> {
#Override
public int compare(Ex4 left, Ex4 right) {
// Compare the entities as specified by the assignment
}
}
Then, you need to accept that as a constructor argument. That, I leave as an exercise to the reader.
Now, to the syntax issue: you're treating primitive int as an Integer, which does have an equals method on it. Primitives aren't objects, hence they can't be dereferenced. You'll want to use the normal equivalence operators (==, >, <) in this situation. You have this already solved in your second-defined compareTo method.
EDIT: After re-reading your requirements, I'm starting to think that your primitive fields are not the right way to go. You should:
Change your fields from int to Integer
Implement Comparable<Ex4> on your entity class
Rely on the default behavior of compareTo() for Integer; that is, your commented code should "just work" (save for the misspell when comparing against C)
Move the secondary compareTo to its own Comparator entity, as described above.
Try this
import java.util.Comparator;
public class Ex4Comparator implements Comparator<Ex4> {
private double x = 0.0;
public Ex4Comparator() {
}
public Ex4Comparator(double x) {
this.x = x;
}
#Override
public int compare(Ex4 o1, Ex4 o2) {
return Double.compare(o1.valueAt(x), o2.valueAt(x));
}
}
Also your equals method doesn't override Object's equals method. You may want to change it to something like
#Override
public boolean equals(Object o) {
if (o instanceof Ex4) {
Ex4 other = (Ex4)o;
return (a == other.a && b == other.b && c == other.c);
}
return false;
}

Java - pass by value [duplicate]

This question already has answers here:
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
Closed 9 years ago.
I was trying something with Integer, and output is freaking me out.
public class CountB
{
public static boolean returnBool(String w, Integer count)
{
for (int i = 0; i < w.length(); i++)
{
if (w.charAt(i) == 'B' || w.charAt(i) == 'b')
{
count++;
}
}
if (count > 0)
return true;
return false;
}
// write the static method “isThisB” here
public static void main(String[] args)
{
// Scanner keyboard = new Scanner(System.in);
// System.out.println("Enter a string: ");
String w = "fgsfbhggbB";//keyboard.nextLine();
Integer count = new Integer(0);
System.out.println(returnBool(w, count));
System.out.println("Number of B and b: " + count);
}
}
Now, Integer being a wrapper class of int, and count being its object, when I pass count from main to returnBool, value of count becomes 3, so it returns true, as java is pass by value count object value should change in main method also, but in main count prints 0.
I want to understand why this is happening?
count++ is just a convenience for
count = Integer.valueOf(count.intValue()+1)
After this operation, your local variable count (in returnBool) refers to another object, and the local variable in your main method keeps pointing to the initial object. You haven't achieved pass-by-reference.
As for Java semantics, there are two similar concepts which are easy to confuse: Java's pass-by-value of object references (in essence, pointers), and true pass-by-reference. Your example stresses this difference.
Java passes the class Integer by Value and not by Reference. If you want to pass it by Reference you'll need an other class like org.apache.commons.lang.mutable.MutableInt from Apache Commons library
There is no pass-by-reference in java. Method parameters are passed by value but that value may be a reference to an object. If the passed object is mutable the changes on it will affect the object outside the method since the object is the same in and out. Integer objects are immutable.
You can pass int[1] or AtomicReference or AtomicInteger or any other object that contains a mutable integer value.
This is your code adapted to AtomicInteger
public class CountB
{
public static boolean returnBool(String w, AtomicInteger count)
{
for (int i = 0; i < w.length(); i++)
{
if (w.charAt(i) == 'B' || w.charAt(i) == 'b')
{
count.incrementAndGet();
}
}
if (count.intValue() > 0)
return true;
return false;
}
// write the static method “isThisB” here
public static void main(String[] args)
{
// Scanner keyboard = new Scanner(System.in);
// System.out.println("Enter a string: ");
String w = "fgsfbhggbB";//keyboard.nextLine();
AtomicInteger count = new AtomicInteger(0);
System.out.println(returnBool(w, count));
System.out.println("Number of B and b: " + count);
}
}

java : return multiple values from a method [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to return multiple objects from a Java method?
lets say N= a+b;
for a number N i want to generate the all possible values a and b. like
if N =7 a and b are (1+6),(2+5),(3+4).
i have coded this logic in a method.
static void sumofNum(int N){
for(int a=1; a<N; a++){
//a+b=N
int b = N-a;
System.out.println(a+","+b);
int next =a+1;
if(next==b | a==b)
return;
}
}
i want to return (1,6),(2,5),(3,4) from this method. next for any N there can be more (a,b) combinations to be returned from this method.
Return a List<String> (assuming "(1,6)" is to be stored as a String). Use one of the implementations of List, such as ArrayList, to construct the list:
static List<String> sumofNum(int N)
{
List<String> result = new ArrayList<String>();
for(int a=1; a<N; a++)
{
int b = N-a;
result.add("(" + a + "," + b + ")");
int next =a+1;
if(next==b || a==b)
return result;
}
return result;
}
If you want to return them as ints, define a object that contains two ints (or abuse points as I have done below) and return a list of those objects. If you define your own object, just replace point with that.
static ArrayList<Point> sumofNum(int N){
ArrayList<Point> result = new ArrayList<Point>();
for(int a=1; a<N; a++){
//a+b=N
int b = N-a;
System.out.println(a+","+b);
int next =a+1;
if(next==b | a==b)
result.add(new Point(a,b));
}
return result;
}
You can get your results from the list with:
results = sumofNum(7);
int a = results.get(0).x; //a = 1
int b = results.get(0).y; //b = 6
In an object oriented (and also functional) style of programming you can pass the result to a consumer an avoid the overhead of storing results in collections or lists.
Example:
static void sumofNum(int N){
for (int a=1; a<N; a++){
//a+b=N
int b = N-a;
consumer.consume(a,b);
int next =a+1;
if (next==b || a==b)
return;
}
}
[ Further improvements of the code are possible (e.g. avoid the inner if and return), ... ]
Consider the nos as (1,6),(2,5),(3,4)
- Now return an ArrayList<String> which contains each value in String form as "1,6" , "2,5", "3,4".
- When you receive the returned ArrayList, then use split() method "," as delimiter to get the 1 and 6 out of "1,6" and so on....

Categories

Resources