I've a Class called Products. This class has a name and a price.
I can create a product the following way:
Product book = new Product();
book.setName("book");
book.setPrice(3);
After that I'm supposed check if this product already exists in the ArrayList I'm supposed to save it to and if it doesn't, then I just put it there. I'm supposed to do this using the following:
public boolean equals(Object obj){
}
The problem is, how am I supposed to do it, if the ArrayList I'm supposed to save the product in, is created and initialised in the public static void main while this boolean is created before the ArrayList even exists?
Should I just make the Class itself an ArrayList, like so?
public class ArrayList<Product>{
}
Don't worry about it's existence. Since you are overiding equals method in your Product class, You can try doing this below
if(yourArayList.contains(book)){
// it existed in the list
}else{
yourArayList.add(book);
}
When you call the contains method it internally calls the equals method of Product method vs the object being passed to it.
This boolean is not created before your ArrayList exists.
You need to overwrite the equals() method of Product like this:
#Override
public boolean equals(Object obj) {
if(obj == this) return true; // Both objects have the same reference -> the objects are equal
if((obj == null) || (obj.getClass() != this.getClass())) return false; // Classes are different -> objects are different
Product p = (Product) obj; // Cast obj into Product
if( (this.getPrice() == p.getPrice()) && (this.getName().equals(p.getName())) ) return true; // Price and name are the same -> both products are the same
return false; // At this point the two objects can't be equal
}
This is how you create an ArrayList:
ArrayList<Product> products = new ArrayList<Product>();
And this is how you add a Product when it doesn't exist in the list:
if(!products.contains(yourProduct)){ // Checks if yourProduct is not contained in products
products.add(yourProduct); // adds yourProduct to products
}
this boolean is created before the ArrayList even exists?
You misunderstood the way equals works. It does not "create" a boolean until you call it with some object as an argument, and it returns a boolean based on the attributes of the object that you pass.
When you define your equals method you provide code to decide equality, but you are not deciding anything at that moment:
#Override
public boolean equals(Object obj){
if (obj == this) return true
if (!(obj instanceof Product)) return false;
Product other = (Product)obj;
if (!other.getName().equals(getName())) return false;
if (!other.getPrice() == getPrice()) return false;
return true;
}
#Override
public int hashCode() {
return 31*getName().hashCode() + getPrice();
}
Now you can use equals to deicide if a list has your Product in one of two ways:
Use contains - this method calls equals to check containment, or
Iterate all objects, and call equals manually.
You don't need to create your own ArrayList class.
If you implement you equals right, it will be called to check if you have it in the list when you execute myList.contains(book)
Actually there is a structure that will let you skip performing the check in your code. You can use the java.util.HashSet. It ensures that no duplicates can be added. In addition it returns the boolean value saying if the element was added. E.g.
Set<Product> mySet = new HashSet<>();
boolean added = mySet.add(book);
Please don't forget the easy to follow rule - when defining the equals, define the hashCode too. If you use an IDE, you can generate them both easily.
Related
I need help. I tried to remove an element from an ArrayList.
I have two lists. One list from a file, the second list from the database.
I need to find the same elements to later remove them from the original list, and thus have a list with differences.
List<BinInternacionalMarcaDEL> listDiff = new ArrayList<BinInternacionalMarcaDEL>();
ListOriginal= binInternacionalRepositoryDEL.findAllByBin();
public List<BinInternacionalMarcaDEL> Differences(List<BinInternacionalMarcaDEL> listA,
List<BinInternacionalMarcaDEL> listB) {
try {
for(BinInternacionalMarcaDEL elementA: listaA){
for(BinInternacionalMarcaDEL elementB: listaB) {
if(elementA.getNumRangoini().compareTo(elementB.getNumRangoini()) == 0 ){
listDiff.add(elementA);
}
}
}
ListOriginal.removeAll(listDiff);
} catch (Exception e) {
LOGGER.error(e.toString());
}
but this doesn't work.
just you can do one thing
listA.retainAll(listB);
here now listA contains only similar elements in both ListA and ListB.
Example:
List<String> listA = new ArrayList<>(Arrays.asList("12","13","15","2","5")) ;
List<String> listB = new ArrayList<> (Arrays.asList("2","12","48","49","55"));
listA .retainAll(listB );
System.out.println(listA ); //[12, 2]
Java list remove and contains methods are implemented using equality of objects. This logic is implemented in hashCode and equal method in your class and all classes in Java inherit this attribute from the Object class.(to be honest ArrayList doesn't use hashCode in implementing remove and contains metheds but in java contract you should implement these two methods together). here when you are adding element to listDiff you are defining your own equality which is based on equality of attribute numRangoini(using compateTo method) and when you request the list class to remove them from list(with removeAll method). removeAll remove them based on the equality of that two object. Since you haven't defined this logic in your own class.
this behaviour is inherited from object class which is based on strict equality. by default two object are equal if they reference the same object.
Solution: define the logic for equality in your own class in equal method. This method should return true if two object has the same attribute value numRangoini. don't forget to define hashCode as well. and here is the rule if two objects are equal they should return the same hashCode.
here is a simple implementation
#Override
public boolean equals(Object obj) {
if(this == obj)
return true;
if(obj == null || obj.getClass()!= this.getClass())
return false;
BinInternacionalMarcaDEL binInternacionalMarcaDEL = (BinInternacionalMarcaDEL)obj;
return (national.getNumRangoini().compareTo(this.getNumRangoini()) == 0);
}
#Override
public int hashCode() {
return this.getNumRangoini().intValue();
}
I am not getting the right answer when I try to use indexOf() of an ArrayList made up of user defined objects. Here is the code that creates one of the objects:
State kansas = new State("KS", 5570.81, 2000)
So, the name of the object is "kansas"
Here is the code that creates the ArrayList and adds the object:
ArrayList<State> allStates = new ArrayList<State>();
allStates.add(kansas);
And here is the code that I try to use to find the index of this object:
System.out.println(allStates.indexOf(kansas));
This is the point at which my compiler (Eclipse) throws me a red X indicating that there is a problem with my code and the problem is that it does not recognize 'kansas'. So I tried this:
String s = "kansas";
System.out.println(allStates.indexOf(s));
and it will run but the result is -1.
I am calling a method from a different class to create the ArrayList as opposed to creating it in the same class as my main method but I'm new enough to coding that I"m not sure if that is where I am going wrong. However, in order for the program that I am writing to work, I need to have data about each of the State objects stored so that I can access it from the main method.
Any advice?
*This is my first time posting a questions and I wasn't sure how much detail to go into so if I'm missing relevant information please let me know :)
method indexOf uses equlas() method to compare objects.
That why you have to override equals method in your custom class (if you planning use class in Map override hashCode method as well).
most IDE can generate these methods (equals and hashCode).
here simple example.
public class State {
private String stateCode;
public State(String stateCode /* other parameters*/) {
this.stateCode = stateCode;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
State state = (State) o;
return stateCode.equals(state.stateCode);
}
#Override
public int hashCode() {
return stateCode.hashCode();
}
}
This is because, String is not your custom object State type. Your array list is a list of all 'State' types, which is why this -
String s = "kansas";
System.out.println(allStates.indexOf(s));
won't work.
What you can do is have a convenience method that iterates through the list and returns the index.
private int getIndexOfState(String stateName) {
for(State stateObject : allStates) {
if(stateObject.getName().equals(stateName))
return allStates.indexOf(stateObject);
}
return -1;
}
Now you can reuse this method to find index of any state name you pass, and whenever the method returns -1, it means the stateName(state) was not found in the list of states.You can pass in 'Kansas' or 'California' or anything as the parameter to the method.
In your method call you say
System.out.println(getIndexOfState("Kansas"));
System.out.println(getIndexOfState("Chicago"));
The return value is -1 because there is no String "kansas" in allStates, and ArrayList#indexOf returns -1 if the element is not present in the list. If you try to add s to allStates, the compiler won't even let you, because State is not a String.
I don't know why you instantiated a String with the value "kansas", but if you need to refer to the State from its name (maybe the name comes from a Scanner input), you will need a Map<String, State>, such as:
Map<String, State> map = new HashMap<>();
map.put("kansas", kansas) // a String and the object named kansas
Then, you can do:
System.out.println(allStates.indexOf(map.get("kansas")))
//or
String s = "kansas";
System.out.println(allStates.indexOf(map.get(s)))
I'm simply trying to find the position of an object in a Customer List, although it's constantly returning false when I use the equals() method.
I now understand that you have to create your own equals method to override the automatic one, yet I can't understand how to create one when I'm comparing a Customer inside a Customer array.
Here are my instance variables:
private Customer[] data;
private int size;
private final static int INITIAL_SIZE = 20;
Here is my method to find the position of the object:
public int findCustomerLocation(String name)
{
int spot = -1;
Customer cus = new Customer(name);
for(int i = 0; i < size ; i++)
{
if((data[i].equals(cus)))
{
spot = i;
System.out.println("spot is:" + spot);
}
else
{
System.out.println("spot not found");
}
}
return spot;
}//findCustomerLocation
(It's returning spot not found)
I'm trying to rewrite the equals method, but I'm a bit stuck, I'm trying to use if it's an instance of another, but it's still returning false
Your equals method just uses the same identity operator (==) as the default Object#equals(). Presumably you intend for Customer objects to be considered equal when some particular information inside them, such as an ID field, is equal. If so, you need to compare those fields inside your equals() (and you should always include every field involved in equals() in your hashCode()).
Something like this might be what you're looking for:
public boolean equals(Object other) {
if(!other instanceof Customer) {
return false;
}
Customer that = (Customer) other;
return this.name.equals(that.name);
}
The equals method should implement the logic that dictates whether a given object is "equal to" the current (this) object. Logically it should not rely on fields or parameters that are not members of the class. In your case, you should not be using the data array or the size field in the equals method. Just add the check on the appropriate fields of Customer.
For example, assuming Customer has a field called name, then the following equals checks if two Customers are equal if they have the same name:
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
Customer other = (Customer) obj;
if (name == null) {
if (other.name != null) {
return false;
}
} else if (!name.equals(other.name)) {
return false;
}
return true;
}
If you're using an IDE like Eclipse, there are shortcuts for automatically overriding both equals() and hashCode() methods in a consistent way. Usually, both methods should use the same class members so that if two objects are equal, their hashcode values are identical.
You are comparing the Customer objects, not their names. Since they are not the same object, equals() will return false. To fix this add the following code to Customer:
public boolean equals(Object obj){
if(obj instanceof Customer){
Customer c = (Customer)obj;
if(c.name.equals(this.name)
return true;
}
return false;
}
EDIT: Sorry for the duplicate post, look at the post by chrylis, and insert obj != null before the instanceof statement
Good luck!
Note that you have to implement hashCode when you implement equals. There are some things to consider to write these methods correctly. To be on the safe side it's best to let an IDE generate these methods. For example, in Eclipse, go Source > Generate hashCode() and equals()...
I made my own class with an overridden equals method which just checks, if the names (attributes in the class) are equal. Now I store some instances of that class in a HashSet so that there are no instances with the same names in the HashSet.
My Question: How is it possible to check if the HashSet contains such an object. .contains() wont work in that case, because it works with the .equals() method. I want to check if it is really the same object.
edit:
package testprogram;
import java.util.HashSet;
import java.util.Set;
public class Example {
private static final Set<Example> set = new HashSet<Example>();
private final String name;
private int example;
public Example(String name, int example) {
this.name = name;
this.example = example;
set.add(this);
}
public boolean isThisInList() {
return set.contains(this);
//will return true if this is just equal to any instance in the list
//but it should not
//it should return true if the object is really in the list
}
public boolean remove() {
return set.remove(this);
}
//Override equals and hashCode
}
Sorry, my english skills are not very well. Please feel free to ask again if you don't understand what I mean.
In your situation, the only way to tell if a particular instance of an object is contained in the HashSet, is to iterate the contents of the HashSet, and compare the object identities ( using the == operator instead of the equals() method).
Something like:
boolean isObjectInSet(Object object, Set<? extends Object> set) {
boolean result = false;
for(Object o : set) {
if(o == object) {
result = true;
break;
}
}
return result;
}
The way to check if objects are the same object is by comparing them with == to see that the object references are equal.
Kind Greetings,
Frank
You will have to override the hashCode method also.
try this..
Considering only one property 'name' of your Objects to maintain uniqueness.
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (name == null ? 0 : name.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
User other = (User) obj;
if (name == null) {
if (other.name != null) {
return false;
}
} else if (!name.equals(other.name)) {
return false;
}
return true;
}
I made my own class with an overridden equals method which just checks, if the names (attributes in the class) are equal.
This breaks the contract of .equals, and you must never do it no matter how convenient it seems.
Instead, if you want to index and look up elements by a certain attribute such as the name, use a HashMap<Name, YourType> to find them. Alternatively, use a TreeSet and pass it a Comparator that compares the name only. You can then remove the incorrect equals method.
There are then three ways if you want to find objects by reference equality:
Your objects have no inherent or useful notion of equality.
Don't implement equals. Leave it to its default. You can then use a HashSet to look for reference equality, and a HashMap or TreeSet to index them by any specific attributes.
Your objects do have a useful, universal notion of equality, but you want to find equivalent instances efficiently anyways.
This is almost never the case. However, you can use e.g. an Apache IdentityMap.
You don't care about efficiency.
Use a for loop and == every element.
HashSet contains uses the equals method to determine if the object is contained - and duplicates are not kept within the HashSet.
Assuming your equals and hashcode are only using a name field...
HashSet<MyObject> objectSet = new HashSet<MyObject>();
MyObject name1Object = new MyObject("name1");
objectSet.add(new MyObject("name1"));
objectSet.add(name1Object);
objectSet.add(new MyObject("name2"));
//HashSet now contains 2 objects, name1Object and the new name2 object
//HashSets do not hold duplicate objects (name1Object and the new object with name1 would be considered duplicates)
objectSet.contains(new MyObject("name1")) // returns true
objectSet.contains(name1Object) // returns true
objectSet.contains(new MyObject("name2")) // returns true
objectSet.contains(new MyObject("name3")) // returns false
If you wanted to check if the object in the HashSet is the exact object you are comparing you would have to pull it out and compare it directly using ==
for (MyObject o : objectSet)
{
if (o == name1Object)
{
return true;
}
}
If you do this alot for specific objects it might be easier to use a HashMap so you don't have to iterate through the list to grab a specific named Object. May be worth looking into for you because then you could do something like this:
(objectMap.get("name") == myNameObject) // with a HashMap<String, MyNameObject> where "name" is the key string.
I have an ArrayList of a class that holds information, and I want to add to objects to this list. I want to check to see if that list already contains a number before adding it to a list.
Normally if it were just a list of strings I would just do something like this
if(!list.contains("this string")){
list.add("this string");
}
but since this is a class, it has more than one variable per index.
An example of the class world be this:
private class From{
private long threadID;
private long date;
private String address;
private String body;
private int type;
private long id;
#Override
public boolean equals(Object obj){
if(obj != null){
if(getClass() != obj.getClass()){
return false;
}else{
final From from = (From)obj;
if((this.address != null) ? (from.address != null) : !this.address.equals(from.address)){
return false;
}
}
}else{
return false;
}
return true;
}
}
I want to see if there is already an entry with the same number, so am I going to have to manually loop through each index and check, or is there an easier way of doing what I want to do?
EDIT:
how i call it
HashSet<From> addresses = new HashSet<From>();
From f = new From();
f.setAddress(messages.getString(3));
f.setBody(messages.getString(0));
f.setDate(messages.getLong(2));
f.setThreadId(messages.getLong(1));
f.setType(1);
if(!addresses.contains(f.address)){
addresses.add(f);
}
Use a Set instead of a List. Sets dont allow duplicates
http://docs.oracle.com/javase/6/docs/api/java/util/HashSet.html
You will also need to override equals in your class so the Set knows if two objects are equal
Example of overriding equals can be found here: How to override equals method in java
You have to override equals(Object o) for this. This is the place where you need to define the logic that would define the equality between two objects.
It is good practice to override hashCode() as well. Read more in the Javadocs for Object.
Another way would be to override equals() for Info object such that two Info objects are equal if they both have the same number. before adding the element into the list just do the equals() test .
You can still use the contains method; A List uses the equals method to determine if the item exists in the list. But you must override equals in your Info object.