Understanding java compiler - java

Assuming I have this two classes, in separate files:
public class Text
{
public String _word;
public Text(String w)
{
_word = w;
}
public String getWord()
{
return _word;
}
public boolean equals (Text other)
{
return ((other!=null)&&(_word.equals(other._word)));
}
public boolean test (Text other)
{
return 1==1;
}
}
2nd class:
public class Sentence
{
public String _word;
public Sentence(String w)
{
_word = w;
}
public String getWord()
{
return _word;
}
public boolean equals (Object other)
{
return ((other!=null) && (other instanceof Sentence)
&& (_word.equals(((Sentence) other)._word)));
}
}
And the following main:
public static void main(String[]args){
Text y1 = new Text("abc");
Sentence z1 = new Sentence ("abc");
**
}
Let's say I run the following command where ** is:
System.out.println (y1.equals(z1));
Everything is ok, and it outputs "false".
But, if I run this command:
System.out.println (y1.test(z1));
The compiler screams "Sentence can not be converted to Text".
Two questions:
Why it works for equals but not for test? y1 is Text, so calling y1.equlas() calls to equlas() inside Text, and there it gets only Text as parameter.
If it DOES work, why the output is false? both "_word" set to "abc".
Thanks!

You've defined an equals(Text) method in Text. However, it doesn't override the existing equals(Object) method that it inherits from Object. Because of this, your equals(Text) method overloads the equals(Object) method in Object. Consequently, you can call y1.equals(z1). Because z1 is a Sentence, the equals(Object) method is the one called. The Sentence object matches Object but not Text. The equals method in Object compares object references to see if they're identical.
The equals method for class Object implements the most discriminating possible equivalence relation on objects; that is, for any non-null reference values x and y, this method returns true if and only if x and y refer to the same object (x == y has the value true).
They're not, so it returns false.
You've defined a test(Text) method in Text. There are no other overloads available, and Sentence doesn't match Text at all, so the compiler complains.
Incidentally, the equals(Object) method you've defined in Sentence is a proper override of equals, checking for null and the class of the argument.

According to the Object class definition, you inherit this in all classes
public boolean equals(Object obj)
In your case y1.equals(z1) is actually executed as y1.equals( (Object) z1), a valid cast since all objects inherit Object. You then have the above method called.

I think in Text.java you wanted to override Object.equals(Object other), but instead of overriding you created an other method with the same name (equals(Text other)), but with different parameter type.
That is why System.out.println (y1.equals(z1)); compiles: that equals call matches the signature equals(Object), which method Text inherits from Object.
On the other hand, System.out.println (y1.test(z1)); fails to compile, since Text has only 1 method with the name test, and its formal parameter type is Text, which doesn't match the type of the actual parameter (Sentence).

Related

compareTo is comparing date but not time JAVA [duplicate]

I constructed a class with one String field. Then I created two objects and I have to compare them using == operator and .equals() too. Here's what I've done:
public class MyClass {
String a;
public MyClass(String ab) {
a = ab;
}
public boolean equals(Object object2) {
if(a == object2) {
return true;
}
else return false;
}
public boolean equals2(Object object2) {
if(a.equals(object2)) {
return true;
}
else return false;
}
public static void main(String[] args) {
MyClass object1 = new MyClass("test");
MyClass object2 = new MyClass("test");
object1.equals(object2);
System.out.println(object1.equals(object2));
object1.equals2(object2);
System.out.println(object1.equals2(object2));
}
}
After compile it shows two times false as a result. Why is it false if the two objects have the same fields - "test"?
== compares object references, it checks to see if the two operands point to the same object (not equivalent objects, the same object).
If you want to compare strings (to see if they contain the same characters), you need to compare the strings using equals.
In your case, if two instances of MyClass really are considered equal if the strings match, then:
public boolean equals(Object object2) {
return object2 instanceof MyClass && a.equals(((MyClass)object2).a);
}
...but usually if you are defining a class, there's more to equivalency than the equivalency of a single field (a in this case).
Side note: If you override equals, you almost always need to override hashCode. As it says in the equals JavaDoc:
Note that it is generally necessary to override the hashCode method whenever this method is overridden, so as to maintain the general contract for the hashCode method, which states that equal objects must have equal hash codes.
You should override equals
public boolean equals (Object obj) {
if (this==obj) return true;
if (this == null) return false;
if (this.getClass() != obj.getClass()) return false;
// Class name is Employ & have lastname
Employe emp = (Employee) obj ;
return this.lastname.equals(emp.getlastname());
}
The best way to compare 2 objects is by converting them into json strings and compare the strings, its the easiest solution when dealing with complicated nested objects, fields and/or objects that contain arrays.
sample:
import com.google.gson.Gson;
Object a = // ...;
Object b = //...;
String objectString1 = new Gson().toJson(a);
String objectString2 = new Gson().toJson(b);
if(objectString1.equals(objectString2)){
//do this
}
The overwrite function equals() is wrong.
The object "a" is an instance of the String class and "object2" is an instance of the MyClass class. They are different classes, so the answer is "false".
It looks like equals2 is just calling equals, so it will give the same results.
Your equals2() method always will return the same as equals() !!
Your code with my comments:
public boolean equals2(Object object2) { // equals2 method
if(a.equals(object2)) { // if equals() method returns true
return true; // return true
}
else return false; // if equals() method returns false, also return false
}
The "==" operator returns true only if the two references pointing to the same object in memory. The equals() method on the other hand returns true based on the contents of the object.
Example:
String personalLoan = new String("cheap personal loans");
String homeLoan = new String("cheap personal loans");
//since two strings are different object result should be false
boolean result = personalLoan == homeLoan;
System.out.println("Comparing two strings with == operator: " + result);
//since strings contains same content , equals() should return true
result = personalLoan.equals(homeLoan);
System.out.println("Comparing two Strings with same content using equals method: " + result);
homeLoan = personalLoan;
//since both homeLoan and personalLoan reference variable are pointing to same object
//"==" should return true
result = (personalLoan == homeLoan);
System.out.println("Comparing two reference pointing to same String with == operator: " + result);
Output:
Comparing two strings with == operator: false
Comparing two Strings with same content using equals method: true
Comparing two references pointing to same String with == operator: true
You can also get more details from the link: http://javarevisited.blogspot.in/2012/12/difference-between-equals-method-and-equality-operator-java.html?m=1
Statements a == object2 and a.equals(object2) both will always return false because a is a string while object2 is an instance of MyClass
Your implementation must like:
public boolean equals2(Object object2) {
if(a.equals(object2.a)) {
return true;
}
else return false;
}
With this implementation your both methods would work.
If you dont need to customize the default toString() function, another way is to override toString() method, which returns all attributes to be compared. then compare toString() output of two objects. I generated toString() method using IntelliJ IDEA IDE, which includes class name in the string.
public class Greeting {
private String greeting;
#Override
public boolean equals(Object obj) {
if (this == obj) return true;
return this.toString().equals(obj.toString());
}
#Override
public String toString() {
return "Greeting{" +
"greeting='" + greeting + '\'' +
'}';
}
}
Your class might implement the Comparable interface to achieve the same functionality. Your class should implement the compareTo() method declared in the interface.
public class MyClass implements Comparable<MyClass>{
String a;
public MyClass(String ab){
a = ab;
}
// returns an int not a boolean
public int compareTo(MyClass someMyClass){
/* The String class implements a compareTo method, returning a 0
if the two strings are identical, instead of a boolean.
Since 'a' is a string, it has the compareTo method which we call
in MyClass's compareTo method.
*/
return this.a.compareTo(someMyClass.a);
}
public static void main(String[] args){
MyClass object1 = new MyClass("test");
MyClass object2 = new MyClass("test");
if(object1.compareTo(object2) == 0){
System.out.println("true");
}
else{
System.out.println("false");
}
}
}
the return type of object.equals is already boolean.
there's no need to wrap it in a method with branches. so if you want to compare 2 objects simply compare them:
boolean b = objectA.equals(objectB);
b is already either true or false.
When we use == , the Reference of object is compared not the actual objects. We need to override equals method to compare Java Objects.
Some additional information C++ has operator over loading & Java does not provide operator over loading.
Also other possibilities in java are implement Compare Interface .which defines a compareTo method.
Comparator interface is also used compare two objects
Here the output will be false , false beacuse in first sopln statement you are trying to compare a string type varible of Myclass type to the other MyClass type and it will allow because of both are Object type and you have used "==" oprerator which will check the reference variable value holding the actual memory not the actual contnets inside the memory .
In the second sopln also it is the same as you are again calling a.equals(object2) where a is a varible inside object1 . Do let me know your findings on this .
In short, == compares two POINTERS.
If the two pointers are equal, then they both point to same object in memory (which, obviously has the same value as itself).
However, .equals will compare the VALUES of whatever is pointed to, returning true iff they both evaluate to the same value.
Thus, two separate strings (i.e., at different addresses in memory) are always != but are .equal iff they contain the same (null-terminated) sequence of chars.
IN the below code you are calling the overriden method .equals().
public boolean equals2(Object object2) {
if(a.equals(object2)) { // here you are calling the overriden method, that is why you getting false 2 times.
return true;
}
else return false;
}

How x.clone().equals(x) is True

I have tried this implementation but i got false for the class x
x.clone().equals(x)
Class X :
public class X implements Cloneable{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
protected Object clone()throws CloneNotSupportedException {
return super.clone();
}
}
Main class :
public class ObjectCloneCopy {
public static void main(String[] args) throws CloneNotSupportedException {
X x = new X();
System.out.println("x.clone().equals(x) - " + x.clone().equals(x));
}
}
Is it mandatory to overload the hashcode() and equals() to get this True ?
Without overriding these methods how this statement gives true?
X x1 = x;
x1.equals(x)
Explain how that could be true, i have seen in this link
You need to override equals() and hashCode() method in your X class.
Else you can't get the correct result from x.clone().equals(x)
Object#clone returns independent of clonning object, so two independent object may not be equals.
As per documentation -
Object#clone -
Creates and returns a copy of this object. The precise meaning of
"copy" may depend on the class of the object. . The general intent is that -
x.clone() != x // true
x.clone().getClass() == x.getClass() // true
and
x.clone().equals(x) // will be true, this is not an absolute requirement.
By convention, the returned object should be obtained by calling
super.clone. If a class and all of its superclasses (except Object)
obey this convention, it will be the case that x.clone().getClass() ==
x.getClass().
Need to override `equals()` and `hashCode()` method in the class `X`.
If not you can't get the correct true for x.clone().equals(x)
For
X x1 = new X()
x1.equals(x)
Since not overriding equals()
x1 and x are considered as same object of X class so it return true
Without overriding it will check the equals() in Object class
public boolean equals(Object obj) {
return (this == obj);
}
Try first to equals() and hashCode() and make thier result based on class attribute value so that when you override , the cloned instance should return the same value of hashCode() and the equals code should return true. check this it may help you .
First Question : x.clone().equals(x) It will return false.
We need override equals & hashcode.Because of the following reason we need to do.
1) Clone will create new instance of x. Reference of two instances are different since both are different reference.
2) If equals & hashcode methods are not overridden, Super class Object#equals will be invoked. This will check the memory location of the object. As per our earlier point both have different address, so it will false.
Second Question : X x1 = x x1.equals(x) return true.
1) x1,x are same object and same location.
2) So even override equals & hashcode methods are not overridden, it will check the memory location and will return true.

Trouble with equals method

I have created a class called student which has an equals method as shown below.
My problem is this.
I create an instance of student class and add it to ArrayList, Now I want to check weather the list contains a duplicate of student object. When i try this with the below equals function its giving wrong result.
for eg.
Student stud1= new Student(101,"Student1");
Student stud5= new Student(105,"Student5");
Student stud6= new Student(105,"Student5");
list1.add(stud1);
list1.add(stud5);
System.out.println(list1.contains( new Student(105,"Student5")));// outputting false
class Student{
int sid;
String sname;
public Student(int sid,String sname){
this.sid=sid;
this.sname=sname;
}
public String toString(){
return ""+this.sid;
}
public boolean equals(Student test){
return this.sid==test.sid;
}
}
but when I replace the equals function with the one below its giving a correct result.. Why is that? Technically there is no difference right? Could you please help me as how is the JVM looking at the code..
public boolean equals(Object cond){
if(cond instanceof Student){
Student test = (Student) cond;
return test.sid==this.sid;
}
return false;
}
The first equals(Student) method doesn't override the Object#equals(Object) method. Hence with that, the list.contains(Student) method will invoke the default Object#equals() method, and which compares the references using ==. So, for two different objects, it will return false.
The contains javadoc states
Returns true if this list contains the specified element. More formally, returns true if and only if this list contains at least one element e such that (o==null ? e==null : o.equals(e)).
You must override equals(Object), in your example you define equals(Student), which is not used when calling list1.contains(.
No, they are not the same.
In order for the equals to work properly, you need to override the method from superclass (Object). And the overridden method signature is
public boolean equals(Object cond){}
By doing this public boolean equals(Student test){} you are effectively overloading the method. Thus it is no longer the call back method and the equals method of Object is getting called.
public boolean equals(Object cond)
and
public boolean equals(Student cond)
has two different method signatures
The first one, You are overriding the Object class's equals method. (Same signature as Object.equals
The second one you overload the method. with different signature.
to override, the method signature must be similar.
That is why equals(Object other) works.

running boolean method from main

I'm trying to compare two integers or double parameters by using the method from main.
I don't understand what the problem is.
The parameters bitterChocolate_amount and milkChocolate_amount
are defined as integers.
Main:
boolean x = equals(bitterChocolate_amount,milkChocolate_amount)
Method:
public boolean equals (Fat other)
{
if (this == other) {
return true;
}
else {
return false;
}
}
The error message is
required: Object
found: int,int
reason: actual and formal argument lists differ in length
1 error
This public boolean equals (Fat other) is your method accept only one argument. But boolean x = equals(bitterChocolate_amount,milkChocolate_amount) in this you passing two argument.
Do like this
boolean x = equals(bitterChocolate_amount,milkChocolate_amount);
Method:
public boolean equals (int bitterChocolate, int milkChocolate)
{
if (bitterChocolate == milkChocolate)
return true;
else
return false;
}
This public boolean equals (Fat other) method accepts only one argument but you are passing 2 arguments here equals(bitterChocolate_amount,milkChocolate_amount) Also as you said to compare 2 integers then the method will be like this
public boolean equals (int other,int someother)
the problem is your actual and formal parameters doesn't match
you can edit your method like this.
boolean x = equals(bitterChocolate_amount,milkChocolate_amount)
Method:
public boolean equals (int value1,int value2)
{
if (value1 == value2)
{
return true;
}
else
{
return false;
}
}
Actually there is no need for an "equals" method. Simply use operators like:
if(int_a == int_b) { // returns true or false
//my code...
}
Take a look: http://docs.oracle.com/javase/tutorial/java/nutsandbolts/operators.html
Like mentioned above, you're trying to pass two arguments (bitterChocolate_amount,milkChocolate_amount) to a method with only one available parameter (Fat other).
Not to mention the parameter type (Fat) is different to the arguments you're trying to pass in (int, int).
I can't really tell from the scope of the code you provided, but since you're calling that from a main class without any mention of an object instance you probably want to be declaring the method as static too.
This is bread and butter stuff here, I think you should be left alone to figure it out yourself as you'll learn a heck of a lot more that way. I'd recommend a good book if you're interested in long term investment; Head First books and Deitel and Deitel are pretty good.
You call method with one parameter and use two parameters.
The error message is self-explanatory
required: Object
found: int,int
The way you defined your equals method, it expects one parameter of type "Fat".
I assume you must have created the Fat class.
Now you are calling this method using two integer parameters, that's why its saying
required :object (of type "Fat")
and found: int, int
Now lets focus on your requirement
If you just want to compare two integer values, modify your equals method to the one defined below
public boolean equals (int value1,int value2)
{
if (value1 == value2)
{
return true;
}
else
{
return false;
}
}
In your equals method, you have used "this", which means you should call it on an object.
So it should be like this
Fat f = new Fat(3);
Fat g = new Fat(4);
f.equals(g)
But in this case, as you are comparing objects, (this==other) will not work as both the objects are different. == compares the object themselves and not the value they are storing. SO I am not sure what you want to achieve.
It will be better to get the right answer if you clarify your requirements.

java why should equals method input parameter be Object

I'm going through a book on data structures. Currently I'm on graphs, and the below code is for the vertex part of the graph.
class Vertex<E>{
//bunch of methods
public boolean equals(Object o){
//some code
}
}
When I try to implement this equals method my compiler complains about not checking the type of the parameter and just allowing any object to be sent it. It also does seem a bit strange to me why that parameter shouldn't be a Vertex instead of an Object. Is there a reason why the author does this or is this some mistake or antiquated example?
#Override
public boolean equals(Object obj)
{
if (!(obj instanceof Vertex)) return false;
else return // blah blah
}
equals(Object) is the method defined in the root - Object. If you don't match the signature exactly, Object's version will be called when someone checks if two objects are equal. Not what you want.
You've probably seen other methods (like Comparator) where you can use the exact time. That's because those APIs were generic-ified with Java 5. Equals can't be because it is valid to call equals with two separate types. It should return false, but it is valid.
equals is a method inherited from Object, is defined to be flexible enough so that you can take any object and test if it is equal to any other object (as it rightfully should be able to do), so how could it be any other way?
Edit 1
Comment from jhlu87:
so is it not good form to write an equals method that has an input parameter of vertex?
You are welcome to create your own overload to any method, including equals, but doing so without changing the name could risk confusing many who would assume that your equals is the one that inherits from Object. If it were my code and I wanted a more specific equals method, I'd name it slightly different from just "equals" just to avoid confusion.
If your method doesn't take an argument of type Object, it isn't overriding the default version of equals but rather overloading it. When this happens, both versions exist and Java decides which one to use based on the variable type (not the actual object type) of the argument. Thus, this program:
public class Thing {
private int x;
public Thing(int x) {
this.x = x;
}
public boolean equals(Thing that) {
return this.x == that.x;
}
public static void main(String[] args) {
Thing a = new Thing(1);
Thing b = new Thing(1);
Object c = new Thing(1);
System.out.println(a.equals(b));
System.out.println(a.equals(c));
}
}
confusingly prints true for the first comparison (because b is of type Thing) and false for the second (because c is of type Object, even though it happens to contain a Thing).
It's because this method existed before generics, so for backward compatabitity it has to stay this way.
The standard workaround to impose type is:
return obj instanceof MyClass && <some condition>;
It is because the author is overriding equals. Equals is specified in java.lang.Object and is something that all classes inherrits from.
See the javadoc for java.lang.Object

Categories