I'm facing the following problem, it´s for a quiz (shuffled answers, not the same amount of answers for every question):
I have two Lists listOfAnswers and listOfUserAnswers (both are type List<Answer>).
Answer is defined as followed:
public class Answer {
int answerId;
int answerIsCorrect;
String answer;
public Answer() {
}
public void setId(int id) {
this.answerId = id;
}
public Answer setAnswer(String answer) {
this.answer = answer;
return this;
}
public void setAnswerIsCorrect(int answerIsCorrect) {
this.answerIsCorrect = answerIsCorrect;
}
public int getId() {
return this.answerId;
}
public String getAnswer() {
return this.answer;
}
public int getAnswerIsCorrect() {
return this.answerIsCorrect;
}
public String toString() {
return String.format("Answer[%s, %s, %s]", this.answerId, this.answerIsCorrect, this.answer);
}
}
The listOfAnswers object holds EVERY answer for each question (specified in listOfQuestions of type List<Question>, but this is not the problem).
The listOfUserAnswers object holds every answer, the user has SELECTED (selected by a checkbox). At this point, the app does not know if the answer selected by the user is right or wrong.
Now, when calculating the result, I want iterate through listOfAnswers and I check, if the answerId (listOfAnswers.get(i).getId()) is also available in listOfUserAnswers.
But how does this work? I can't check with listOfUserAnswers.contains(...), I think. Or am I wrong?
Please, comment if you have trouble understanding....
You can't check if listOfUserAnswers.contains() because you haven't defined an Answer.equals() method. You would have to iterate through both lists like so:
for(Answer answer : listOfAnswers) {
for(Answer userAnswer : listOfUserAnswers) {
if(answer.getId() == userAnswer.getId()) {
//answer matches
}
}
}
Alternatively, you could define an Answer.equals() method:
#Override
public boolean equals(Object obj) {
return obj instanceof Answer && ((Answer)obj).answerId == this.answerId;
}
Now instead of a nested loop, you can do:
for(Answer answer : listOfAnswers) {
if(listOfUserAnswers.contains(answer) {
//answer matches
}
}
EDIT: As mentioned in the comments, you should always override hashCode() when overriding equals(). In this case, the simplest implementation would be:
#Override
public int hashCode() {
return answerId;
}
To use the ArrayList.contains() method you'll need to override the Object.equals() method. So in this case you'd add to your Answer class something like:
public boolean equals(Object o){
if(o instanceof answer){
return this.answerId == ((Answer) o).answerId;
} else return false;
}
And then you can use it.
Checking for listOfUserAnswers.contains() is not possible unless you override the following method:
#override
public boolean equals(Object o){
if(this.answerId == ((Answer)o).answerId ) return true;
return false;
}
You can, just overwrite equals method as follows:
public boolean equals(Object o) {
if(!(o instanceof Answer) ) return false;
return answerId == ((Answer)o).answerId;
}
and call contains.
Related
I am trying to Implement a class named Parade using an ArrayList, which will manage instances of class Clown. Each Clown needs to be identified by all object data String for their name, int id and double size. I join a new Clown to the end of the Parade. Only the Clown at the head of the Parade (i.e., the first one) can leave the Parade. In addition, I write a method called isFront that takes a Clown as parameter and returns true if the passed clown is at the front of the parade otherwise returns false. Create a test application to demonstrate building a parade of three or four clowns and include your own name. Then, remove one or two, and add another one or two. Also, test the isFront method by passing different clowns to the method.
I have a code but it is not returning true for the isFront method, I am trying to use contains method I also tried to use Comparable interface Clown but it did not work that well. Not sure what to do.
import java.util.ArrayList;
public class Main
{
public static void main(String[] args)
{
Parade circus = new Parade();
circus.addClown(new Clown("Bobby",9,12.0));
circus.addClown(new Clown("Clair", 2, 11.0));
circus.addClown(new Clown("Tony",6,10.0));
circus.addClown(new Clown("Sarah",3,5.0));
circus.display();
System.out.println(circus.isFront(new Clown("Bobby", 9, 12.0)));
}
}
import java.util.ArrayList;
public class Parade
{
private static ArrayList<Clown> parade;
private int top;
public Parade()
{
top=0;
parade= new ArrayList<Clown>();
System.out.println(parade);
}
public void addClown(Clown c)
{
parade.add(c);
top++;
}
public void removeClown() //(Clown c)
{
parade.remove(0);
top--;
}
public void display()
{
System.out.println(parade);
}
public void getData()
{
parade.get(0);
}
public void setData()
{
parade.set(1,new Clown("Claire",2,5.0));
System.out.println(parade);
}
public int getTop()
{
return top;
}
public boolean isFront(Clown c)
{
return !parade.isEmpty() && c.equals(parade.get(0));
}
//exceptions
}
public class Clown
{
private String name;
private int id;
private double size;
public Clown(String name, int id, double size)
{
this.name=name;
this.id=id;
this.size=size;
}
public String getName()
{
return name;
}
public int getId()
{
return id;
}
public double getSize()
{
return size;
}
public String toString()
{
return name.toString() + id + size;
}
public boolean equals(Object o) {
if (o instanceof Clown c) {
return this.getName().equals(c.getName()) && this.getId() == c.getId() && this.getSize() == c.getSize();
}
return false;
}
}
their is not much info in our textbook about this stuff Java FOundations 5th e Lewis like working with objects and arraylists it skips it and assumes you already know it lol..
Firstly, objects in Java are, by default, compared by reference. So, even if you create two Clown objects with the exact same properties, Java sees them as different objects because both those object references are not the same, they are both referring to different memory locations. You can override this behavior and ask Java to compare it as you want by overriding the equals() method of the Object class:
public class Clown {
private String name;
private int id;
private double size;
public Clown(String name, int id, double size) {
this.name=name;
this.id=id;
this.size=size;
}
public String getName() {
return name;
}
public int getId() {
return id;
}
public double getSize() {
return size;
}
#Override
public boolean equals(Object o) {
if (o instanceof Clown) {
Clown c = (Clown) o;
return this.getName().equals(c.getName());
}
return false;
}
#Override
public int hashCode() {
return this.getId();
}
#Override
public String toString() {
return name.toString() + id + size;
}
}
This will help with contains()(it internally uses equals()).
Secondly, you can just compare your clown with the first clown to see if it is the one at the front:
public boolean isFront(Clown c) {
return !parade.isEmpty() && c.equals(parade.get(0));
}
The isFront() method will return true if the parade is not empty and the clown c is equal to to the first clown in the parade. get(0) retrieves the first clown in the parade.
As per your comment, if you want that two clowns be equal only if all their properties are equal, change your equals method to:
#Override
public boolean equals(Object o) {
if (o instanceof Clown) {
Clown c = (Clown) o;
return this.getName().equals(c.getName()) &&
this.getId() == c.getId() &&
this.getSize() == c.getSize();
}
return false;
}
The equals() method is of the Object class which is the parent class of all Java classes. It defines how to compare two objects.
Its signature is as follows:
public boolean equals(Object obj)
As we're overriding, its signature must be the same in the derived class, in our case in class Clown. Its parameter is of type Object not Clown. Any type can be converted to Object, if I compare an object of Clown to another type, like:
Clown c = new Clown("X", 1, 10);
if ( c.equals(objectOfAnotherType) ) {..}
it will still work.
So we use the instanceof operator to check if that another object is also a Clown. If it is not an instance of Clown, we return false but if it is, we convert/cast that object to Clown, only then we can call getName() and other getter methods:
if (o instanceof Clown) {
Clown c = (Clown) o; //Casting happens here
return this.getName().equals(c.getName()) &&
this.getId() == c.getId() &&
this.getSize() == c.getSize();
}
return false;
Java 14 introduced a shortcut for this, instead of these steps:
if (o instanceof Clown) {
Clown c = (Clown) o;
we can simply write:
if (o instance of Clown c)
which does the casting for us and stores it in c.
Lastly, I have also overriden Object.hashCode() because you have to when you override equals(), here's why.
I'm trying to figure out how to test if a list of objects contains an object that contains a particular string as an attribute.
So here Is my list of objects
ArrayList<mObject> objectsList;
And here is my mObject class
public class mObject {
String x = "True";
}
And here I try to make some kind of test
if(ObjectsList.contains(object.x == "True")){
return true;
} else {
return false;
}
I know the syntax is kind of ridiculous, but how can I make it technically correct?
For previuos versions of Java 8:
public class MObject {
private String x = "True";
public String getX() {
return x;
}
public void setX(String x) {
this.x = x;
}
}
You can iterate over the list:
ArrayList<MObject> objectsList; //Init your object list.
for(MObject object : objectsList) {
if(object.getX().equals("True")) {
return true;
} else {
return false;
}
}
Java 8:
List<mObject> list = ObjectsList.stream().filter(obj -> obj.x.equals( "True")).collect(Collectors.toList()).;
if (list.size() != 1) {
return false;
} else {
return true;
}
and, please, observe java naming conventions
for Java 8 you can use
objectsList.stream().anyMatch(myObject -> myObject.x.equals("True"));
please look at the code standards about naming variables (lowercase start and camel case) and classes (uppercase start)
PS: As your variable is a string with "True" value - are you sure not wanting to have a boolean?
I override equals() method to be able to use .contians() because it comparing objects using equals(),as your List is List<mObject> (List of custom object) so i had to override the .equals() to be able to use .contains() probably
public class mObject {
private String x = "True";
public String getX(){
return x;
}
public void setX(String x){
this.x=x;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final mObject other = (ttt) obj;
if (!Objects.equals(this.x, other.x)) {
return false;
}
return true;
}
}
To make your test :-
if(ObjectsList.contains(object) && object.getX().equals("True")){
return true;
} else {
return false;
}
Please see the difference between == and .equals() when comparing string
from this and that link
What do I need to write inside the " if " statement in order to check if the object's variable (number) is equal to any of the object's variables (number) inside my array?
public class Question{
private int number;
private String questionString;
private int index = 0;
public Question(int number, String questionString){
if(number < 0){
System.out.print("Number cannot be negative!");
}
if(questionString.equals(null) || questionString.trim().isEmpty()){
System.out.print("Question cannot be empty!");
}
this.number = number;
this.questionString = questionString;
}
public boolean equals(Object o){
if(o instanceof Question){
for(int i = 0; i < index; i++){
if(.... ){
}
}
return true;
}
return false;
}
}
Test Class (main Class), ofc not yet completed I just hope it gives you enough information, on how to proceed on my Question class:
public class Test{
String name;
Question[] questions;
public Testi(String name, int nrQuestions){
}
public static void main(String[]args){
}
}
This should do:
public boolean equals(Object o){
if (o == null )
return false;
if(o instanceof Question){
if (((Question)o).number == this.number ){
if (this.questionString.equals(((Question)o).questionString)){
return true;
}
}
}
return false;
}
Be careful though, if you're implementing equals() you should also implement hashCode(). It's your "model" that should make clear when two objects are equal. In your case, I would say that when two Question's number are the same, then the Question is also the same. If not, you should also add questionString to the check
From your last comment, I think I now understand your REAL issue: You tried to use the equals() method to compare an object to an array of objects that you pass to this method, right? The call to equals would look like this:
Question[] questions;
question.equals(questions);
Technically this is possible with Java, but strongly discouraged I would say. equals() should only be used to compare to one object at a time (and stick to the hashCode/equals contract).
So I suggest you to do something like this:
//your application code
public boolean equals(Object obj){
if (obj instanceof Question){
return (((Question)obj).number == this.number);
}
return false;
}
//use this to obey the equals/hashCode contract
public int hashCode() {
return this.number;
}
// your test code -------------
public void testQuestions(Question testAgainstThisObject, Question[] testQuestions) {
for (Question testThisQuestion : testQuestions) {
assertTrue(testAgainstThisObject.equals(testThisQuestion));
}
}
Another way would be to use a specialised method in Question.java, something like this:
public boolean isThisContained(Question[] questions) {
for (Question question : questions) {
if (this.equals(question)) {
return true;
}
}
return false;
}
I've been testing a code and stumbled across a problem: Should you call super.equals() method in subclass that can override some of the methods used in equals() method of the super class?
Let's consider the following code:
public abstract class Item {
private int id;
private float price;
public Item(int id, String name, float price, String category) {
this.id = id;
this.name = name;
this.price = price;
this.category = category;
}
public int getID() {
return id;
}
public float getPrice() {
return price;
}
#Override
public boolean equals(Object object){
if(object instanceof Item){
Item item = (Item) object;
if( id == item.getID()
&& price == item.getPrice())
{ return true; }
}
return false;
}
}
And the subclass DiscountedItem:
public class DiscountedItem extends Item {
// discount stored in %
private int discount;
#Override
public boolean equals(Object object) {
if(object instanceof DiscountedItem){
DiscountedItem item = (DiscountedItem) object;
return (super.equals(item)
&& discount == item.getDiscount()
);
}
return false;
}
public int getDiscount() {
return discount;
}
#Override
public float getPrice() {
return super.getPrice()*(100 - discount);
}
}
I've been just re-reading Angelika Langer's secrets of equals(), where she even states:
There is agreement that super.equals() should be invoked if the class has a superclass other than Object.
But I think it's highly unpredictable when the subclass will override some of the methods. For instance when I compare 2 DiscountedItem objects using equals, the super method is called and item.getPrice() is dynamically dispatched to the correct method in the subclass DiscountedItem, whereas the other price value is accessed directly using variable.
So, is it really up to me (as I should implement the method correctly) or is there a way around it?
Compare instance variables directly rather than comparing an instance variable to its related getter method.
For example, change
&& price == item.getPrice())
to
&& this.price == item.price)
The getter method is unnecessary since private instance variables are only inaccessible outside the class structure.
Note:
I previously recommended the following:
&& this.getPrice() == item.getPrice())
While it will work in the question's example, it is not well suited for all cases. Consider if the subclass DiscountedItem declared the method getPrice as such:
#Override
public float getPrice() {
return Math.floor(super.getPrice());
}
This would result in the false equivalence:
DiscountedItem firstItem = DiscountedItem(1, "", 1.1, "");
DiscountedItem secondItem = DiscountedItem(1, "", 1.0, "");
firstItem.equals(secondItem); // Returns true despite different prices.
The implementation of equals should depend on state and type, but not functionality. You went wrong in your base class:
#Override
public boolean equals(Object object){
if(object instanceof Item){ // Type check- good!
Item item = (Item) object;
if( id == item.getID() // Depends on functionality- bad!
&& price == item.getPrice()) // Depends on functionality- bad!
{ return true; }
}
return false;
}
item.getID() and item.getPrice(), as you've noticed, can be overwritten to break the contract of Item.equals().
#Override
public boolean equals(Object object){
if(object instanceof Item){ // Type check- good!
Item item = (Item) object;
if( id == item.id // Depends on state- good!
&& price == item.price) // Depends on state- good!
{ return true; }
}
return false;
}
This will never be broken by a child class. Further, it enables the child to meaningfully delegate to it.
#Override
public boolean equals(Object object) {
if(object instanceof DiscountedItem){
DiscountedItem item = (DiscountedItem) object;
return (super.equals(item)
&& this.discount == item.discount
);
}
return false;
}
The child only needs to worry about comparing the data that it owns.
Oh my, I guess I just had to post the question to get it..
To get rid of the problem, instead of directly accessing variables - call the getters!
#Override
public boolean equals(Object object){
if(object instanceof Item){
Item item = (Item) object;
if( this.getID() == item.getID()
&& this.getPrice() == item.getPrice())
{ return true; }
}
return false;
}
This code no longer has the problem when overriding methods.
If you call the equals of the DiscountedItem when can you have a problem?
If something is DiscountedItem and something else is Item these two
are never equal as per equals. Right? So I don't see a problem if you
always call the getters.
Also, you need to override hashCode if you override equals.
public class Car
{
private String name;
public int id;
public Car(String name, int id)
{
this.name = name;
this.id = id;
}
#Override
public boolean equals(Object ob)
{
if (!(ob instanceof Car))
{
return false;
}
Car that = (Car)ob;
return this.id == that.id;
}
#Override
public int hashCode()
{
return id;
}
// this class also got getters and setters
Then I got another class
public class CarList
{
private Collection<Car> cars;
public CarList()
{
cars = new HashSet<>();
}
public boolean insertCar(Car car)
{
return cars.add(car);
}
My question is: How to properly override equals() and hashCode() method, where I consider 'id' and 'name' attribute for object comparsion and hashCode calculation ( so there is no possibility to have 2 objects with the same name and ID - because in this code as it is - it only takes 'id' attribute for object comparsion)?
As of Java 7, there are static methods on Objects that makes implementing hashCode and equals easier. This should work well, assuming you don't want to use getClass() instead of instanceof to determine type compatibility. That depends on how subclasses of Car should compare to Cars.
#Override
public boolean equals(Object ob)
{
if (!(ob instanceof Car))
{
return false;
}
Car that = (Car)ob;
return Objects.equals(this.id, that.id) && Objects.equals(this.name, that.name);
}
#Override
public int hashCode()
{
return Objects.hash(id, name);
}
Instead of using
if (!(ob instanceof Car))
{
return false;
}
You should think about using
if (getClass() != obj.getClass())
return false;
Lets assume you have ForWdCar extends Car and TwoWdCar extends Car with equal name and id.
Do you want them to be equal? 1st solution,
Do you want them to be unequal? 2nd solution
You don't care, such cases don't happen? Second solution, it's faster.