Does the equals method work with objects? If so, how? - java

I have a program that is zoo and in the zoo there are branched subgroups of animals that are reptiles. When I do an equals method the main program compiles and it runs. I'm confused how does java know to use the equals method if I'm comparing objects and not specifically int or String?
public class Zoo {
public static void main(String[]args) {
Animal a=new Animal("Bob");
Reptile komodo= new Reptile("Snakey");
komodo.bask();
a.size=3;
komodo.size=5;
System.out.println(a);
System.out.println(komodo);
Turtle t= new Turtle("Slowy");
t.hide();
t.size=6;
t.numlegs=4;
System.out.println(t);
System.out.println(t.equals(komodo));
}
}
public class Animal {
public String name;
public boolean equals(Animal other) {
return other.size==this.size;
}
public Animal(String s) {
name=s;
}
public void setName(String n) {
this.name=n;
}
public void eat(String meal) {
System.out.println("chump chump yummy "+meal);
}
public int size;
public String toString() {
return "I am "+name+" and I'm "+size+" cm long";
}
}
public class Reptile extends Animal {
public Reptile(String n) {
super(n);
numlegs=0;
}
public Reptile(String n, int l) {
super(n);
numlegs=l;
}
public void bask() {
System.out.println("basking...");
}
public String toString() {
return super.toString()+numlegs+" legs";
}
public int numlegs;
}
public class Turtle extends Reptile {
public Turtle(String n) {
super (n,4);
shellColor="Brown";
}
public void hide() {
System.out.println("you cant see me");
}
public String toString() {
return super.toString()+" and my shell is"+ shellColor;
}
public String shellColor;
public void bask() {
super.bask();
System.out.println("turtle is basking...");
}
}

You're not overriding the Object#equals method, but overloading it. In your method declaration you use Animal type instead of Object:
public boolean equals(Animal other)
A good overriding of the method would be using the instanceof operator. Showing an example:
#Override
public boolean equals(Object other) {
if(other instanceof Animal) {
Animal otherAnimal = (Animal)other;
//comparison logic...
}
return false;
}
More info on the subject:
Best practices regarding equals: to overload or not to overload?
Overriding Object.equals VS Overloading it

For your question on how java knows how to compare objects,
you need to override the equals method
public boolean equals(Object other){
// return true or false based on your logic
}
While comparing, equals method is used.
You can have a look at this good tutorial which explains the significance of the equals method.
http://www.thejavageek.com/2013/06/26/what-is-the-significance-of-equals-method-in-java/
Also, only overriding equals is not enough if you are using objects into collections those use hashing. You will find a good tutorial at
http://www.thejavageek.com/2013/06/28/significance-of-equals-and-hashcode/

Every class inherits the Object class silently. And the Object class has a equals method. So if any class doesn't override the equals method then it will use the default implementation of Object.equals.
From the doc
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).
From the source code of Object.equals
public boolean equals(Object obj) {
return (this == obj);
}
So If any object doesn't have it's own implementation of equals then the equals method will simply check if the object reference is same or not.
So get a desired result from equals you need to implement by your own as alread suggested in other answer

Related

Restriction of type parameter in method

Given 3 classes:
class Fruit implements Comparable<Fruit> {
private final int weigth;
public Fruit(int weight) {
this.weigth = weight;
}
#Override
public int compareTo(Fruit other) {
return Integer.compare(this.weigth, other.weigth);
}
public int getWeigth() {
return this.weigth;
}
}
class Apple extends Fruit {
public Apple(int weight) {
super(weight);
}
}
class Orange extends Fruit {
public Orange(int weight) {
super(weight);
}
}
I need to fix a code adjusting compareTo method to not allow comparing different Types of Fruit.
I understand that currently Apple and Orange have superclass Fruit which can hold a reference value to both subclasses. I cannot figure out how to correctly implement generics to fix the problem.
The compareTo method should show a compile-time error if the argument does not match the object which invokes the method.
Try this:
public abstract class Fruit<F extends Fruit<F>> implements Comparable<F> {
public int compareTo(F other) {
...
}
}
public final class Apple extends Fruit<Apple> {
// not needed to actually write the compareTo method, it'll just work.
}

Using compareTo in Java to Sort

Basically i'm attempting to write a compareTo that does the comparison based on the value of compareByWord. If compareByWord is true, I want it to compare based on the word, but if it's false, I want it to compare based on count.
class WordCount implements Comparable //Error saying WordCount must implement the inherited abstract method Comparable.compareto (Object)
{
String word;
int count;
static boolean compareByWord;
public WordCount(String aWord)
{
setWord(aWord);
count = 1;
}
private void setWord(String theWord)
{
word=theWord;
}
public void increment()
{
count+=1;
}
public static void sortByWord()
{
compareByWord = true;
}
public static void sortByCount()
{
compareByWord = false;
}
public String toString()
{
String result = String.format("%s (%d)",word, count);
return result;
}
public String getWord()
{
return word;
}
public int getCount()
{
return count;
}
#Override
public int compareTo(WordCount other) { //Error saying compareTo (WordCount) of type WordCount must override or implement a supertype method.
if (compareByWord == true)
{
return word.compareTo(other.getWord());
}
if (compareByWord == false)
{
return count.compareTo(other.getCount()); //Error saying it cannot invoke compareTo int on primitive type int.
}
return 0;
}
}
My class was perfect before I tried to implement this, not sure where I'm going wrong here. Any and all help is much appreciated.
Change the declaration to
class WordCount implements Comparable<WordCount> { // generic version
The method signature in Comparable<WordCount> is compareTo(WordCount obj) while for the raw version it's compareTo(Object obj).
With the usage of #Override, the compiler makes sure that you actually override the parent method. And the problem is that compareTo(WordCount obj) does not override compareTo(Object obj).
must implement the inherited abstract method Comparable.compareto (Object)
So pass Object, not WordCount. Now you're trying to overload this function, not override.
Use Integer count not int count. Integer is an object which implements Comparable whereas int is a primitive as the error message describes. For javadocs:
public final class Integer
extends Number
implements Comparable<Integer>
Make sure you change your accessor methods to use Integer as well of course.
That will take care of your final error.

using equals or instanceof in toString

Ok guys I have a program with a 'MartianManager' class: *Note code is not complete still have some missing pieces just supplied entire code for reference of somewhat how it is going to look when complete
import java.util.ArrayList;
public class MartianManager {
private ArrayList<Martian> martians;
private ArrayList<Martian> teleporters;
public void addMartian(Martian m) {
martians.add(m);
if(m instanceof GreenMartian)
teleporters.add(m);
}
//public Object clone() {
public Martian getMartianClosestToID(int id) {
}
public void groupSpeak() {
for(Martian m : martians) {
m.speak();
}
}
public void groupTeleport(String dest) {
}
}
and Martian class:
public abstract class Martian implements Cloneable {
int id;
public Martian(int id) {
this.id = id;
}
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
public int getId() {
return id;
}
public boolean equals(Object o){
return this.getId() == ((Martian)o).getId();
}
public abstract void speak();
public String toString(){
String str = "";
if (this instanceof GreenMartian) {
str = "Green martian" + id;
}
if (this instanceof RedMartian) {
str = "Red martian" + id;
}
return str;
}
}
it is extended with GreenMartian:
public class GreenMartian extends Martian implements ITeleport{
public GreenMartian(int id) {
super(id);
}
public void speak() {
System.out.println(id + "Grobldy Grock");
}
public void teleport(String dest) {
System.out.println(id + "teleporting to " + dest);
}
}
also extended with RedMartian:
public class RedMartian extends Martian {
public RedMartian(int id) {
super(id);
}
public void speak() {
System.out.println(id + "Rubldy Rock");
}
}
I actually have a few questions , but for now my question is in the toString of the Martian class. It should return a string like this: "Red [or Green] martian" +id. I need to determine the type of Martian, I started to use the instanceof but like this "Martian couldn't be resolved to a variable". I'm trying to determine if this would be the best way or if an equals() would be the best way to determine the type?
Also this is my first time using "clone" so not sure how it works exactly, but had a thought is there a way to determine what the "clone" was and determine it that way?
Thanks for any and all help!
No
public String toString(){
String str;
if (Martian instanceof GreenMartian) {
}
in abstract Martian class is a bad idea. You don't want your parent class to depend on its children.
Implement a toString() method in each subclass instead and let polymorphism do its work.
If you absolutely have to
if (Martian instanceof GreenMartian) {
is wrong. You use instanceof as so
instanceOfClass instanceof SomeClass
In this case you get a reference to instanceOfClass with the this keyword, since you are calling the method on an instance
this instanceof GreenMartian
You really should not have a parent class reference any classes that extend it. This is bad practice (and might not actually work, i haven't tested). You should really just override the toString function in each extended class.
public class GreenMartian extends Martian implements ITeleport{
public GreenMartian(int id) {
super(id);
}
public void speak() {
System.out.println(id + "Grobldy Grock");
}
public void teleport(String dest) {
System.out.println(id + "teleporting to " + dest);
}
#Override
public String toString() {
return "GreenMartian: whatever info you'd like to include.";
}
}
Now, if you want to have a similar format for all subclasses, you have two options. One is to call the toString method of the parent class, and prepend that to the subclass's toString method.
#Override
public String toString() {
return super.toString() + "GreenMartin: info.....";
}
//The parent toString could look like this:
#Override
public String toString(){
return "Martian( ... put any parent class info here, id ect)";
}
The final output for a GreenMartian toString call then may look like this:
Martian(id:23) GreenMartian(planet:greenburg)
A Third option would be to have a common string format in the parent class. For example, in the parent class, include this attribute:
protected static final String format = "Class: %s, id: %s, info: %s";
Then, in the subclass toString, you can do this:
#Override
public String toString() {
return String.format(format,this.getClass().toString(),id,myInfo);
}
You can use String name = this.getClass().getSimpleName() to get the name of your class. Then you can check name.substring(0,1).equals("G") or name.substring(0,1).equals("R") to detect Red or Green.
FWIW, it should be if (this instanceof GreenMartian) - but IMHO whenever you are tempted to use such an downcast (upcast??), it is an sign of bad OO design. Rather write a specialized toString()method for your martians. And you should really check for o==null in your equals() method.
Martian is not a variable. Try this instead:
if(this instanceof GreenMartian)

Equals override for String and Int

I have a list in that list I created an object. By using the contains() method, I want to check whether the object already exists or not. For that, I override the equals() method. Everything is perfect upto this. But when I try to do the same thing for String and int the equals() override doesn't not work. Why is it like this? I just posted some sample code for reference.
public class Test
{
private int x;
public Test(int n)
{
x = n;
}
public boolean equals(Object o)
{
return false;
}
public static void main(String[] args)
{
List<Test> list = new ArrayList<Test>();
list.add(new Test(3));
System.out.println("Test Contains Object : " + list.contains(new Test(3))); // Prints always false (Equals override)
List<String> list1 = new ArrayList<String>();
list1.add("Testing");
String a = "Testing";
System.out.println("List1 Contains String : " + list1.contains(a)); // Prints true (Equals override not working)
}
}
String and Integer are both final classes, so you cannot subclass them. Therefore you cannot override their equals methods.
You can, however, subclass ArrayList and create your own contains implementation builds on the existing one.
There is no need for overriding the equals method of Integer or String as they are already implemented and work well.
However, if you want to do it anyways, this would be one way of doing it (Delegation Pattern):
public class MyString {
private String myString;
#Override
public boolean equals(Object o)
return false;
}
// add getter and setter for myString
// or delegate needed methods to myString object.
}
Of course, then you must be using this class, not the String class in your lists.
Regarding Tim's answer you can do something like this:
import java.util.*;
import java.lang.*;
import java.io.*;
class Ideone{
public static void main (String[] args) throws java.lang.Exception
{
MyString my = new MyString();
String testString = "bb";
my.setMyString(testString);
System.out.println(my.equals(testString));
}
}
class MyString {
private String myString;
#Override
public boolean equals(Object o){
return o.equals(myString);
}
public String getMyString(){
return myString;
}
public void setMyString(String newString){
myString = newString;
}
}
The output is true.

Why is the toString() method being called when I print an object?

I can't seem to understand why when I use println method on the quarter object, it returns the value of the toString method. I never called the toString method why am I getting the return value?
public class Main {
public static void main(String[] args) {
Quarter q = new Quarter();
Nickel n = new Nickel();
System.out.println(q);
System.out.println(n);
}
}
public abstract class Money {
private int value;
public Money(int v) {
value=v;
}
public abstract int getValue();
protected int myValue() {
return value;
}
public abstract String toString();
}
public abstract class Coin extends Money {
public Coin(int value) {
super(value);
System.out.println("I am a coin, my value is " + getValue());
}
}
public class Quarter extends Coin {
public Quarter () {
super(25);
}
public int getValue() {
return myValue();
}
public String toString() {
return "A Quarter is "+getValue();
}
}
public class Nickel extends Coin {
public Nickel () {
super(5);
}
public int getValue() {
return myValue();
}
public String toString() {
return "A "+this.getClass().getName()+ " is "+getValue();
}
}
On Refering to java docs what i undestand is that,
When you call PrintStream class print(obj) / println(obj) method then internally it called write method with arguement as String.valueOf(obj) shown below :
public void print(Object obj) {
write(String.valueOf(obj));
}
Now String.valueOf(obj) does the task of calling to String method as shown below :
/**
* Returns the string representation of the <code>Object</code> argument.
*
* #param obj an <code>Object</code>.
* #return if the argument is <code>null</code>, then a string equal to
* <code>"null"</code>; otherwise, the value of
* <code>obj.toString()</code> is returned.
* #see java.lang.Object#toString()
*/
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}
Because PrintStream.println has an overload that takes an Object, and then calls its toString method.
Because this is how this function operates: it formats the primitive types for you, but when you pass it an object, it will call .toString() on it.
If you don't override it, it will output the default .toString() implementation (Class#somenumber) which is not really useful...
When you are directly trying to print an object, by default it will call the toString method you need to override that toString method to print the attributes of your class.
Because all classes in java are subclasses of java.lang.Object , so whenever you try to call System.out.println() method to print object, it calls the toString() method of Object class.
For Security Reasons the method prints a hashcode, not the values of that object,
but you have inherited that method in your class and extended its definition to print object values
public String toString() {
return "A Quarter is "+getValue();
}
So you get a return value.

Categories

Resources