I have implemented HashMap for storing hotel booking entry.But I'm getting null values on .get(object) method even it contains all keys and returning keys correctly.I already override equals() & hashCode() methods in two different class (bookingSeason & entry) because bookingSeason class is used in some other class also and it works correctly but in entry class it does not work.
public class Entry {
String code;
List<BookingSeason> booking=new ArrayList<>();
public Entry(String code) {
this.code=code;
}
#Override
public boolean equals(Object o) {
if(o==null)
return false;
if(!(o instanceof Entry))
return false;
Entry room=(Entry) o;
return this.code.equals(room.code)&&
this.booking.equals(room.booking);
}
#Override
public int hashCode() {
return Objects.hash(code,booking);
}
}
public class BookingSeason {
LocalDate startDate;
LocalDate endDate;
public BookingSeason(LocalDate startDate,LocalDate endDate) {
this.startDate=startDate;
this.endDate=endDate;
}
#Override
public boolean equals(Object object)
{
if(object==this)
return true;
if(!(object instanceof BookingSeason))
return false;
BookingSeason bS=(BookingSeason) object;
return Objects.equals(startDate,bS.startDate)&& Objects.equals(
endDate,bS.endDate);
}
#Override
public int hashCode() {
return Objects.hash(startDate,endDate);
}
}
public class Hotel {
List<BookingSeason> bookPeriod=new ArrayList<>();
HashMap<Long,Entry> roomEntry =new HashMap<>();
long num;
Entry newRoom=new Entry();
for(int i=101;i<=199;i++) {
num=i;
newRoom.code="A";
newRoom.code=newRoom.code.concat(String.valueOf(i));
roomEntry.put(num,new Entry(newRoom.code));
System.out.println(roomEntry.get(i));
}
}
roomEntry.put(num,new Entry(newRoom.code));
uses the long value num to enter the new Entry object into the hashmap.
System.out.println(roomEntry.get(i));
uses the int value i to try to get the Entry object.
But, since
Long.valueOf(11).equals(Integer.valueOf(11)) == false
it will not found the entry. You need to pass a long/Long value to the get method. Therefore, either using
System.out.println(roomEntry.get(num));
or using
System.out.println(roomEntry.get((long) i));
will solve your problem.
For reference see also What are the reasons why Map.get(Object key) is not (fully) generic
Solution:
Simply change the for loop from this:
for(int i=101;i<=199;i++) {
to this:
for(long i=101;i<=199;i++) {
Explanation:
What you have done wrong here is that you are trying to pass an int into the get method of HashMap<Long, Entry>.
Since the HashMap uses longs as keys, whenever the get method sees you try to use some other type of incompatible value, like int, it just returns null!
Although the integer i you passed into get has the same hash code as the long num, the get method treats them as "not the same".
Why?
Think about what would happen if get allowed you to use an object that is of unrelated type to the key type of the hash map to access a value:
class A {
#Override
public int hashCode() { return 1; }
}
class B {
#Override
public int hashCode() { return 1; }
}
// in some method
HashMap<A, Object> map = new HashMap<>();
map.put(new A(), "some stuff");
map.get(new B()); // returns "someStuff"! makes no sense, right?
Related
There is a Object of Example, the filed id is unique.
And I Suppose there are many elements in the map, What's the quickest way to remove an example of id = 1 from the map.
public class Solution {
#Data
public static class Example {
// unique key
int id;
Object filed;
}
public static void main(String[] args) {
// Suppose there are many elements in the map
HashMap<Example, Object> map = new HashMap<>();
int id = 1;
Example example = new Example();
example.setId(id);
map.put(example, new Object());
// How to quickly delete example of id = 1
System.out.println(map);
}
}
You must override equals and hashCode method in Example class. Post which when you will invoke map.remove(example) it will remove it. In your equals and hashCode method you must use field id as equality or comparison factor.
class Example {
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Example)) return false;
Example that = (Example) o;
return id == that.id;
}
#Override
public int hashCode() {
return Objects.hash(id);
}
}
Note: Above is not a compiled code and just a snippet.
I have Set of Object which has existing values and getting a new Set values as an update. If the new Set does contain the old Object then I do nothing, if the new Set contains new Object then I want send create update and if the new Set doesn't contain an existing object then I want send a delete update.
Object has two fields :
private PreferenceType preferenceType;
private String preferenceValue;
Currently I am comparing the existing Set objects against new Set objects and if I don't find any existing object in new set then sending the delete update.
private void sendDeletePreferenceMessage(Set<AccountPreference> existingAccountPreferences, Set<AccountPreference> accountPreferencesFromRequest) {
int counter = 0;
for(AccountPreference accountPreference : existingAccountPreferences) {
for(AccountPreference accountPreference1: accountPreferencesFromRequest) {
if(accountPreference.getPreferenceType().equals(accountPreference1.getPreferenceType()) &&
accountPreference.getPreferenceValue().equals(accountPreference1.getPreferenceValue()))
counter++;
}
if(counter == 0) {
accPrefDeleteSender.send(accountPreference);
}
}
}
And also comparing the new set of objects against existing set of Objects to find the new updates that I want send as a create update
private void sendCreatePreferenceMessage(Set<AccountPreference> accountPreferencesFromRequest, Set<AccountPreference> existingAccountPreferences) {
int counter = 0;
for(AccountPreference accountPreference : accountPreferencesFromRequest) {
for(AccountPreference accountPreference1: existingAccountPreferences) {
if(accountPreference.getPreferenceType().equals(accountPreference1.getPreferenceType()) &&
accountPreference.getPreferenceValue().equals(accountPreference1.getPreferenceValue()))
counter++;
}
if(counter == 0) {
accPrefCreateSender.send(accountPreference);
}
}
}
This works perfectly but I believe this could be simplified in a better way. Any suggestion of doing this better!
You are using two AccountPreference Objects: one with id field, and another without id. I don't know if it's possible without using interfaces or abstract classes. Nevertheless, according to your comments it seems to me you're confused how to override Object.equals method, so I'll give you an example:
class MyObjectWithId {
private long id;
private String someField;
public String getSomeField() {
return someField;
}
#Override
public boolean equals(Object other){
if (this == other) return true;
if (other == null || !other.getClass().isInstance(MyObject.class)) return false;
MyObject myObject = (MyObject) other;
return this.getSomeField().equals(myObject.getSomeField());
}
}
class MyObject {
private String someField;
public String getSomeField() {
return someField;
}
#Override
public boolean equals(Object other){
if (this == other) return true;
if (other == null || !other.getClass().isInstance(MyObjectWithId.class)) return false;
MyObjectWithId myObjectWithId = (MyObjectWithId) other;
return this.getSomeField().equals(myObjectWithId.getSomeField());
}
}
As you can see, you can ask if the two different types of Object are equal (in this case, there isn't need for overriding hashCode).
Now you should be able to do the rest (regarding your original question about two Sets)
Set has a method boolean contains(Object o).
You don't need two for loops, just iterate through one Set and check if another Set contains() the object!
You also need to override the boolean equals(Object o) in the POJO!
class MyObject {
private PreferenceType preferenceType;
private String preferenceValue;
#Override
public boolean equals(Object o){
if (this == o)
return true;
if (o == null || o.getClass()o.getClass() != getClass())
return false;
if(this.getPreferenceType().equals(o.getPreferenceType()) && this.getPreferenceValue().equals(o.getPreferenceValue()))
return true;
return false;
}
}
}
Trying to realize simple task stuck into strange problem:
class User{
String login;
String pwrd;
User(String lg,String pw){
this.login=lg;
this.pwrd=pw;
}
public String toString(){
return this.login;
}
public boolean equals(String a){
return this.login.equals(a);
}
public boolean equals(User t){
return this.login.equals(t.toString());
}
}
public class Foo{
public static void main (String[] args)
{
HashMap<User,Boolean> a=new HashMap<>();
User a1=new User("asd","123"),a2=new User("asd","134");
a.put(a1,false);
a.put(a2,false);
System.out.println(a.containsKey(a2));
System.out.println(a.containsKey("asd"));
}
}
As a result I expected both containsKey checks to be true. Further in code it would be used more and more. So the first thing is to understand why it behaves so and if possible fix it. Any help appreciated.
The keys of your Map are User instances, so a.containsKey("asd") will never return true, since "asd" is a String.
BTW, you didn't override Object's equals, which expects an Object argument. This means that a.containsKey(a2) also returns false, since a1==a2 is false.
A correct implementation of equals would be :
#Override
public boolean equals(Object other){
if (!(other instanceof User))
return false;
User u = (User) other;
return this.login.equals(u.login);
}
As Andy mentioned, you must also override hashCode, so that if a.equals(b) is true then a.hashCode()==b.hashCode().
EDIT :
I think you can make a.containsKey("asd") return true if you override equals in a way that treats String instances as equal to your User instance if they match the login property :
#Override
public boolean equals(Object other){
if (other instanceof User) {
User u = (User) other;
return this.login.equals(u.login);
} else if (other instanceof String) {
String u = (String) other;
return this.login.equals(u);
}
return false;
}
#Override
public int hashCode()
{
return login.hashCode();
}
I never tried such an implementation of equals, but based on my understanding of HashMap, it might work.
However, such an implementation of equals would violate the contract of equals as defined in the Javadoc of Object, since "asd".equals(a1) will return false even though a1.equals("asd") is true.
EDIT:
After checking the implementation of HashMap, I found this implementation of equals won't work, since the code of containsKey(key) compares the key against the keys of the existing entries instead of the other way round, and String.equals(obj) will always return false if obj is not a String. I guess there's a good reason not to break the contract of equals.
You need to override public boolean equals(Object other) and inside that method check for correct type of other object passed. Please note that the object passed might be null as well.
public class User {
public boolean equals(Object other) {
//Is the same
if(other == this) {
return true;
}
//Other is a user as well - Includes null-check (thanks, Kevin!)
if(other instanceof User) {
//equal if usernames are equal
return login.equals(other.login);
}
//anything else - not equal / null, whatever
return false;
}
}
I'm needing to get a unique method identifier to use as a key on a HashMap.
I'm trying to do something using stacktrace and reflection and user the method signature. But the problem is I didnĀ“t find a way to retrive the complete method signature (to avoid methods overload).
Edited
I would like that somethink like this works:
public class Class1 {
HashMap<String, Object> hm;
public Class1() {
hm = new HashMap<String, Object>();
}
public Object method() {
if (!containsKey()) {
Object value;
...
put(value);
}
return get();
}
public Object method(String arg1) {
if (!containsKey()) {
Object value;
...
put(value);
}
return get();
}
public Boolean containsKey() {
if (hm.containsKey(Util.getUniqueID(2)) {
return true;
} else {
return false;
}
}
public void put(Object value) {
hm.put(Util.getUniqueID(2), value);
}
public Object get() {
String key = Util.getUniqueID(2);
if (hm.containsKey(key) {
return hm.get(key);
} else {
return null;
}
}
}
class Util {
public static String getUniqueID(Integer depth) {
StackTraceElement element = Thread.currentThread().getStackTrace()[depth];
return element.getClassName() + ":" + element.getMethodName();
}
}
But the problem is the two methods, with this strategy, will have the same ID.
How can I work around?
You can append + ":" + element.getLineNumber() but you'd still have to worry about the case where two overloaded methods are put on one long line.
Looking at the StackTraceElement methods, it doesn't seem possible to get a unique method identifier this way. Besides, the code is not very readable in my opinion.
I'd suggest you try to be more explicit and do
if (hm.containsKey("getValue(int)") {
...
}
or something similar.
I have a java LinkedList which contains several custom objects of the same type.
LinkedList<myClass> = new LinkedList<myClass>();
Within my objects I have a specific value
class myClass(){
public int id;
}
I want to be able to return the index of the linked list for a match of a specific value, i.e: Find the LinkedList index where the object id = 7
I have looked into using indexof, contains, and containsall, but without any luck (index of always returns -1).
Is this something I can do with a prebuild libary, or am I going to have to extend my own search function for custom objects?
Override the equals method on your myClass class so the LinkedList could find the object:
public class myClass {
private int id; //it should be private, not public
//other attributes...
//getters and setters...
#Override
public void equals(Object o) {
if (o == null) return false;
if (o == this) return true;
if (o instanceof myClass) {
myClass x = (myClass)x;
return x.getId() == this.id;
}
return false;
}
}
Since you're overriding equals, you should also override the hashCode method:
#Override
public int hashCode() {
return this.id;
}
The reason for this is explained in the Object class 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.
Maybe you shoud simple store your objects in an HashMap<key,value>
you put an object in it as value with a key. If you want to search for an Object you just get it over the key. So for example you take your class and use the objectID as key if its unique.
HashMap<Integer, myClass> list = new HashMap<Integer, myClass>();
list.put(newId, new MyClass(newId)); //just an example!
to find it now you just need one line like this:
list.get(newId);
if the newId does not exsist it return null.
LinkedList compares Object using their equals() method. So if you want two instances of your class to be considered equal when they have the same ID, you must override the equals() method:
#Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (o == null) {
return false;
}
if (o.getClass() == this.getClass()) {
return this.id == ((MyClass) o).id;
}
return false;
}
When overriding equals(), hashCode() must also be overridden, because two equals objects MUST have the same hashCode:
#Override
public int hashCode() {
return id;
}
Note that if you don't want two instances to be considered equal when they have the same ID, then you have no choice other than iterating the list and finding the first element which has the same ID as the instance you're looking for. Or you must use another data structure, like a Map<Integer, MyClass> for example.
This can be implemented in terms of List's indexOf() method, all you have to do is override equals() and hashChode() in myClass to specify that the comparisons must be made using the id attribute (here is an explanation of why you need to override both methods). Simply add this methods to myClass:
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
myClass other = (myClass) obj;
if (id != other.id)
return false;
return true;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
return result;
}
Now to find the index of an element with id == 7 do something like this:
int idx = myList.indexOf(new myClass(7));
That is, assuming that there exists a constructor in myClass that takes the id as a parameter.
You can do it like this
list.indexOf(new Object() {
#Override
public boolean equals(Object o) {
MyClass mine = (MyClass) o;
return mine.id == yourValue;
}
});