I'm writing a program and I'm supposed to check and see if a certain object is in the list before I call it. I set up the contains() method which is supposed to use the equals() method of the Comparable interface I implemented on my Golfer class but it doesn't seem to call it (I put print statements in to check). I can't seem to figure out whats wrong with the code, the ArrayUnsortedList class I'm using to go through the list even uses the correct toString() method I defined in my Golfer class but for some reason it won't use the equals() method I implemented.
//From "GolfApp.java"
public class GolfApp{
ListInterface <Golfer>golfers = new ArraySortedList<Golfer> (20);
Golfer golfer;
//..*snip*..
if(this.golfers.contains(new Golfer(name,score)))
System.out.println("The list already contains this golfer");
else{
this.golfers.add(this.golfer = new Golfer(name,score));
System.out.println("This golfer is already on the list");
}
//From "ArrayUnsortedList.java"
protected void find(T target){
location = 0;
found = false;
while (location < numElements){
if (list[location].equals(target)) //Where I think the problem is
{
found = true;
return;
}
else
location++;
}
}
public boolean contains(T element){
find(element);
return found;
}
//From "Golfer.java"
public class Golfer implements Comparable<Golfer>{
//..irrelavant code sniped..//
public boolean equals(Golfer golfer)
{
String thisString = score + ":" + name;
String otherString = golfer.getScore() + ":" + golfer.getName() ;
System.out.println("Golfer.equals() has bee called");
return thisString.equalsIgnoreCase(otherString);
}
public String toString()
{
return (score + ":" + name);
}
My main problem seems to be getting the find function of the ArrayUnsortedList to call my equals function in the find() part of the List but I'm not exactly sure why, like I said when I have it printed out it works with the toString() method I implemented perfectly.
I'm almost positive the problem has to do with the find() function in the ArraySortedList not calling my equals() method. I tried using some other functions that relied on the find() method and got the same results.
Your equals method should take an Object argument, not a Golfer. The equals(Golfer) method is overloading the Comparable's equals(Object) method but does not implement it. It's simply an overloaded method no other code knows about, so it doesn't get called.
public boolean equals(Object obj)
{
if(!(obj instanceof Golfer)) return false;
Golfer golfer = (Golfer)obj;
String thisString = score + ":" + name;
String otherString = golfer.getScore() + ":" + golfer.getName() ;
System.out.println("Golfer.equals() has bee called");
return thisString.equalsIgnoreCase(otherString);
}
Related
I've got 2 classes, car extends vehicle, Why, when I'm trying to print a new created car object the output isn't equal as I thought.
I'm running it on Eclipse, java 11
public class vehicle_13 {
private int years;
public vehicle_13(int y) {
years=y;
}
public int years() {
return years;
}
public String driving() {
return "Can drive";
}
public int speed() {
return 50;
}
public String toString() {
return "years = "+years()+"\n"+this.driving()+"\n"+"speed = "+this.speed()
+"\n"+this.money_per(); // driving() = this.driving()
}
public int money_per() {
return years*10;
}
}
public class car_13 extends vehicle_13 {
public car_13(int y) {
super(0);
}
public int speed() {
System.out.println(super.driving());
return super.speed()*2;
}
}
I expect the output of this car object .toString() to be:
years = 0
Can drive
Can drive
speed = 100
0
but the actual output is:
Can drive
years = 0
Can drive
speed = 100
0
When you concatenate the string like this:
return "years = " + years() + "\n" + this.driving() + "\n"
+ "speed = " + this.speed() + "\n" + this.money_per();
It has to execute each of the methods before it creates the string. After all, it's the result of executing the method that gets added to the string. So the println in the speed method is called when this.speed() is evaluated, then the concatenated string is returned by toString, and then the result is passed to System.out.println. So the println in speed runs before the println in main, not in the middle of it.
P.S: Long concatenation like this, is better suited to the String.format method
return String.format("years = %d\n%d\nspeed = %d\n%d",
years(), driving(), speed(), money_per());
You have called super.driving in the sub-class and that is what is evaluated first. Therefore it prints out "Can drive" first, before the result of the toString as you expected.
I have two classes, one named Bird the other Runtime. The bird class creates birds - name, latin name. The Runtime class has 4 methods, only one is important for this question, that is the 'add' method. The add method when called upon needs to take input from the user that is name and latin name, these are saved into a string variable 'name' and 'latin name' and I call the Bird class constructor and pass in these string variables into its parameter and finally it is added to an ArrayList. However I get duplicate values, if I were to write the same bird twice.
I have tried to convert the ArrayList into a set and convert it back again into an ArrayList, i did this within the add method, this did not work. I suspect it is down to my poor understanding of how objects are stored in an ArrayList. I also created a getName method within the Bird class, so I can use list.get(i).getName, and if the name is equal to the one typed by the user, it prompts the user accordingly, if not it is added to my ArrayList. This also did not work. I also tried a for loop that would go through the ArrayList and an if statement would determine if the name typed by the user exists within the ArrayList, this also did not work, the attempt was early on so I can't remember exactly the error message, but the add method is called from within a while loop, and I think the error message was concurrent modification, I'm not entirely sure so please ignore that, my point is showing the various solutions I tried.
Below is The Bird class
public class Bird{
int obeservation = 0;
String name;
String latinName;
public Bird(String name, String latinName){
this.name = name;
this.latinName = latinName;
}
public void addBird(String name, String latinName){
this.name = name;
this.latinName = latinName;
}
public String getName(){
return this.name;
}
public String statistics(){
return this.name + " (" + this.latinName + ") : " +
this.obeservation + " observation";
}
}
Below is the Runtime class
public class Runtime {
ArrayList<Bird> birds = new ArrayList<Bird>();
Scanner scan = new Scanner(System.in);
public void scan() {
System.out.println("?");
String answer = scan.nextLine().trim();
while (!answer.equalsIgnoreCase("EXIT")) {
System.out.println("?");
answer = scan.nextLine().trim().toUpperCase();
if (answer.equalsIgnoreCase("ADD")) {
add();
} else if (answer.equalsIgnoreCase("OBSERVATION")) {
observation();
} else if (answer.equalsIgnoreCase("STATISTICS")) {
System.out.println("jhjh");//just to see if this is
working
statistics();
}
}
}
below is the add method, also what I've commented is the attempts,
currently the add method does not have an if statements to decide duplicates.
public void add() {
System.out.print("Name: ");
String name1 = scan.nextLine().trim().toUpperCase();
System.out.print("Latin Name: ");
String latinName1 = scan.nextLine().trim().toUpperCase();
birds.add(new Bird(name1, latinName1));
/*
Bird newBird = new Bird(name1, latinName1);
for (int i = 0; i < birds.size(); i++) {
if (birds.get(i).getName().equals(name)) {
System.out.println("Bird already exist");
return;
} else {
birds.add(newBird);
}
}
/*
* hBirds.addAll(birds); birds = new ArrayList<Bird>();
birds.addAll(hBirds);
*
* // Bird newBird = new Bird(name, latinName);
* /* if(birds.contains(name)){
* System.out.println("That name already exist");
* return;
* }else{
* birds.add(newBird(name, latinName));
*
* }
*/
}
The statistics method prints out the ArrayList, a foreach loop that goes through the ArrayList prints it out. The expected result if I input seagull twice should be one seagull value not two. How do i reject the duplicate?
You can have two approaches here:
First: Traverse through ArrayList, if you can't find the same bird, add it to ArrayList. It is a worse approach.
Second: Store birds inside HashSet. In this case, you need to override .hashCode() and .equals(Object obj) methods. It is a better approach.
Before talking about how to generate .hashCode() and .equals(Object obj) methods, I want to mention about .hashCode() method and HashSet<T>.
HashSet<T>s provide a unique set of the elements inside. To achieve this, .hashCode() method of a class is used. If you override .hashCode() method in any class, you can get the benefit of using HashSet<T>s. If you don't override this method, Java automatically returns the memory address of the object. That's why your HashSet<Bird> was including duplicate elements.
.hashCode() and .equals() methods can be generated by lots of IDEs. I copied and pasted your Bird class to Eclipse. By using Alt+Shift+S -> h for Eclipse or Alt+Insert -> equals() and hashCode() for IntelliJ, automatically generated the methods below:
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((latinName == null) ? 0 : latinName.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + obeservation;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Bird other = (Bird) obj;
if (latinName == null) {
if (other.latinName != null)
return false;
} else if (!latinName.equals(other.latinName))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (obeservation != other.obeservation)
return false;
return true;
}
If you add these methods(I encourage you to generate in your IDE) to Bird class, you can use HashSet<Bird>. To avoid duplicates, simply add all of your Bird objects into defined HashSet<Bird>. You don't need any other data structure or equality check to control if any two Bird type objects are equal.
You will just need to change your object collection from ArrayList<Bird> birds = new ArrayList<Bird>(); to Set<Bird> birds = new HashSet<>();.
Move the add out of the loop:
for (int i = 0; i < birds.size(); i++) {
if (birds.get(i).getName().equals(name1)) {
System.out.println("Bird already exist");
return;
}
}
birds.add(new Bird(name1, latinName1));
I am having trouble writing my main method within my car class. My class code is written as following;
public boolean compare (Car otherCar) {
return (model.equals(otherCar.model) && year == otherCar.year);
}
My problem is i am having trouble writing my main method i need to compare my "ferrari" car object with my "cobra" car object. I need to use an if/else statement and the method compare to compare the ferrari obj with the
cobra obj. And need to output "Same" if they are the same, or "Different" if they are different. All my other methods have been working fine besides this one.
Edit:
private String model;
private int year;
// default constructor
public Car()
{
model = "NA";
year = 0;
}
// overloaded constructor
public Car (String newModel, int newYear)
{
model = newModel;
year = newYear;
}
// mutator methods
public void setModel (String newModel)
{
model = newModel;
}
public void setYear (int newYear)
{
year = newYear;
}
// accessor methods
public String getModel()
{
return model;
}
public int getYear()
{
return year;
}
public boolean compare (Car otherCar)
{
return (model.equals(otherCar.model) && year == otherCar.year);
}
public void print()
{
System.out.println(model + " (" + year + ")");
}
}
My question is how should i write the if - else statement in my main method to compare these two objects using the compare method
Edit 2:` {
// Create an object of the class Car named ferrari
Car ferrari = new Car();
// Use the print method to print all information about the ferrari object.
ferrari.setModel("Ferrari");
ferrari.setYear(2010);
ferrari.print();
// Create an object of the class Car named cobra, passing parameters "Cobra" and 1967.
Car cobra = new Car("Cobra", 1967);
// Print information about the Cobra object using get methods.
System.out.println(cobra.getModel() + " " + cobra.getYear());
// Change the model of the cobra object to "Shelby Cobra".
cobra.setModel("Shelby Cobra");
// Change the year of the cobra object to 1963.
cobra.setYear(1963);
System.out.println(cobra.getModel() + " " + cobra.getYear());
// Use an if/else statement and the compare method to compare the ferrari obj with the
`
In your main method, you can simply write an if else for comparing cars and printing out like this,
if (ferrari.compare(cobra)) {
System.out.println("Both cars are same.");
} else {
System.out.println("Both cars are different.");
}
Another note, for printing objects values, you should better override toString() method that way you don't need to implement your print() method like you did. You can implement toString method like this,
public String toString() {
return String.format("model: %s, year: %s", model, year);
}
And then your if else can be written like this and will look better,
if (ferrari.compare(cobra)) {
System.out.println("("+ferrari + ") AND (" + cobra + ") cars are same");
} else {
System.out.println("("+ferrari + ") AND (" + cobra + ") cars are different");
}
Which will give following output,
(model: Ferrari, year: 2010) AND (model: Shelby Cobra, year: 1963) cars are different
I am having trouble with my call to the method makeNoise in the Pets class. I call the makeNoise method through another class, Humans, that has a makePetMakeNoise method:
public void makePetMakeNoise()
{
int randnum = (int)(Math.random() *5);
pet.makeNoise(randnum);
}
And I set the pets' canMakeNoise boolean when I create it: Cat a = new Cat("Critter", "Meow", true);
When I call the Humans' makePetMakeNoise method, I only get a printout like so: Critter remains silent instead of: Meow Critter. Why is this, and how do I fix it? Thanks.
public class Pets
{
String name;
String noise;
boolean canMakeNoise;
public Pets(String pname, String pnoise, boolean pcanmakenoise)
{
name = pname;
noise = pnoise;
pcanmakenoise = canMakeNoise;
}
public void makeNoise(int number)
{
if(canMakeNoise==true)
{
for(int i=0; i<number; i++)
{
System.out.println(noise + " " + name);
}
}
else if(canMakeNoise==false)
{
System.out.println(name + " *remains silent*");
}
}
public void eat()
{
System.out.println(name + " is eating...");
}
}
It looks like the assignment for "canMakeNoise" in the constructor is reversed, i.e. assign canmakenoise = pcanmakenoise.
Change this line from
pcanmakenoise = canMakeNoise;
to
canMakeNoise = pcanmakenoise;
You assigned the constructor parameter pcanmakenoise with the value of canMakeNoise which is currently null.
pcanmakenoise = canMakeNoise;
Default boolean value is false.
canMakeNoise is always false; Hence below condition is always called.
else if(canMakeNoise==false)
Reference ::
https://msdn.microsoft.com/en-us/library/83fhsxwc.aspx
https://www.google.com/search?q=c%23+default+boolean+value&ie=utf-8&oe=utf-8
I have an array of objects that I want to compare to a target object. I want to return the number of objects that exactly match the target object.
Here is my count method:
public int countMatchingGhosts(Ghost target) {
int count=0;
for (int i=0;i<ghosts.length;i++){
if (ghosts[i].equals(target));
count++;
}
return count;
And here is my equals method:
public boolean equals(Ghost other){
if(this == other) return true;
if( !(other instanceof Ghost) ) return false;
Ghost p = (Ghost)other;
if (this.x == p.x && this.y == p.y && this.direction==p.direction && this.color.equals(p.color))
return true;
else
return false;
I run some test code, and I expect 1 matching only, but I get 3 instead. Do you see any errors?
There is a ; at the end of your if:
if (ghosts[i].equals(target));
^
This makes count++; happen always irrespective of what your equals method returns.
You should override this function:
public boolean equals(Object other) { }
Do note the Object class being used in method's signature instead of Ghost. Your can use #Override annotation to get a compiler error if you are not using method signature correctly.
#Override
public boolean equals(Object other) { }
Having said that, what's probably happening in your code is what the other answer is stating...
Just thought I add that while implementing the equals method in your code, you must also implement (override) the hashCode method. This is a general contract that you must follow for the best performances.
Below is an excerpt from Joshua Bloch's book "Effective Java"
Item 9: Always override hashCode when you override equals
A common source of bugs is the failure to override the hashCode method. You
must override hashCode in every class that overrides equals. Failure to do so
will result in a violation of the general contract for Object.hashCode, which will
prevent your class from functioning properly in conjunction with all hash-based
collections, including HashMap,HashSet, and Hashtable.
Here is the contract, copied from the Object specification [JavaSE6]:
• Whenever it is invoked on the same object more than once during an execution
of an application, the hashCode method must consistently return the
same integer, provided no information used in equals comparisons on the
object is modified. This integer need not remain consistent from one execution
of an application to another execution of the same application.
• If two objects are equal according to the equals(Object) method, then calling
the hashCode method on each of the two objects must produce the same
integer result.
And just like Pablo said, if you use anything other than the Object class in your equals method signature, you aren't actually overriding the equals method, and your program won't work as expected.
Take for example this small program that copies a List to a Set(which cannot contain duplicates) and prints the new Collection. Try swapping equals(Object obj) with equals(Item obj) and see what happens when you run the program. Also, comment out the hashCode() method and run the program and observe the difference between using it and not.
public class Item {
private String name;
private double price;
private String countryOfProduction;
public Item(String name, double price, String countryOfProduction) {
this.setName(name);
this.setPrice(price);
this.setCountryOfProduction(countryOfProduction);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public String getCountryOfProduction() {
return countryOfProduction;
}
public void setCountryOfProduction(String countryOfProduction) {
this.countryOfProduction = countryOfProduction;
}
public String toString() {
return "Item Name: " + getName() + "\n" +
"Item Price: N" + getPrice() + "\n" +
"Country of Production: " + getCountryOfProduction() + "\n";
}
#Override
public boolean equals(Object obj) {
if(!(obj instanceof Item)) {
return false;
}
if(obj == this) {
return true;
}
Item other = (Item)obj;
if(this.getName().equals(other.getName())
&& this.getPrice() == other.getPrice()
&& this.getCountryOfProduction().equals(other.countryOfProduction)) {
return true;
} else {
return false;
}
}
public int hashCode() {
int hash = 3;
hash = 7 * hash + this.getName().hashCode();
hash = 7 * hash + this.getCountryOfProduction().hashCode();
hash = 7 * hash + Double.valueOf(this.getPrice()).hashCode();
return hash;
}
public static void main (String[]args) {
List<Item> items = new ArrayList<>();
items.add(new Item("Baseball bat", 45, "United States"));
items.add(new Item("BLUESEAL Vaseline", 1500, "South Africa"));
items.add(new Item("BLUESEAL Vaseline", 1500, "South Africa"));
Collection<Item> noDups = new HashSet<>(items);
noDups.stream()
.forEach(System.out::println);
}
}