In this piece of code i pass a name into a method that modifies the String literal name but not the object itself, when the code exits the method, the object (as identified by the hashcode) is the same, however not the name that is modified in the method.
How should i explain this?
public class ObjectContentsPassByReferenceApp {
private static void modifyObject(Bus bus) {
bus.setName("SBS Transit");
}
public static void main(String args[]) {
Bus bus;
bus = new Bus();
bus.setName("Trans Island Bus");
System.out.println("Bus initially set to (hashcode): " + bus);
System.out.println("Bus name: " + bus.getName());
modifyObject(bus);
System.out.println("After calling modifyObject (hashcode): " + bus);
System.out.println("Bus name: " + bus.getName());
}
}
class Bus {
private String name;
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
Run results:
Bus initially set to (hashcode): sg.java.concepts.passByReference.Bus#8d2ed0
Bus name: Trans Island Bus
After calling modifyObject (hashcode): sg.java.concepts.passByReference.Bus#8d2ed0
Bus name: SBS Transit
You haven't overridden hashCode - therefore it will use the implementation in java.lang.Object, which doesn't vary over the course of an object's lifetime. You haven't overridden equals either... which means that a.equals(b) will only return true for Bus a and Bus b if a and b refer to the exact same object - rather than objects with equal name.
Note that the names in your code suggest that Java uses pass by reference. It doesn't - it always uses pass by value, but those values are always either primitives or references - never actual objects. The same is true for simple assignment etc.
In your code, you're creating a single Bus object. Think of it as a real life bus. It has a name painted on it, and a serial number embossed on it (the latter being the hash code). When you call the method, that's telling the method how to get to the Bus object - it's not creating a new Bus. The method comes and paints over the name with a new one, but that does nothing to the serial number, which is the same as it ever was.
Also note that name is not a string literal - it's a string variable. Its initial value comes from a string literal, but changing the value later does nothing to the original string object.
If you want the hashcode to depend on a variable (i.e. name) then you'll need to override the hashCode method. A simple example:
public class Bus {
private String name;
public int hashCode() {
return name.hashCode();
}
}
The hashCode implementation in java.lang.Object does not use any kind of reflection to look up variables, so you almost always need to override hashCode.
Note that you should always override equals if you override hashCode and vice versa.
There are a bunch of useful tools for helping you implement hashCode. Check out Apache Commons lang and take a look at their HashCodeBuilder class.
Related
I was reading about Immutable objects in java.
There is a statement which states - "Immutable objects are thread-safe".
I need more clarification for the above statement:
If I have a shared resource of type 'String' which is shared with multiple threads (say 3)
And if one of the thread make changes to the shared reference, it will create a new String object and that will available only with that Thread object and other threads will not get to know about the changes made by one of the thread.
Will it not lead to data inconsistency?
So could anyone please help me understand this?
Thanks in advance.
An object of an immutable class is always thread-safe. However, the reference to such an object doesn't have anything to do with that. It might be or it might not be thread-safe, depending on how the class that contains the reference to this thread-safe object (a String object, for example) and the methods to manipulate such a reference.
See this example below, to illustrate the explanation:
public class User {
private string name;
public User(String name) {
this.name=name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name=name;
}
}
So, even though String is an immutable and thread-safe class, the reference to it in the class User above isn't thread-safe because its methods could be concurrently changing this reference to new String objects.
If you wanted it to be thread-safe, there would be many options. One of them would be to set all methods that can change the name object as synchronized.
Immutable types (in any language) are special reference types.
Their uniqueness lies in the fact that when they are changed they are replaced with an entirely new instance which reflects the previous state + the change
Lets say 2 threads running a function which receive an immutable reference type object as a parameter ( and of course i'll use string for this example)
// pseudo code !!
main()
{
var str = "initialState";
new Thread(Do,str,1).Start();
new Thread(Do,str,2).Start();
}
void Do(string arg,int tid)
{
int i = 0;
while(true)
{
arg += "running in thread " + tid + "for the " + i + "time";
Console.WriteLine(arg);
}
}
This program while print in parallel the number of occurrences running in each thread with out effecting what was printed in the other thread.
Why ?
If you think about it string is a reference type, it is passed by reference and not by value, meaning it is not copied only a copy of the reference occurs.
And yet though it was initially the same object. after the first change it is no longer and a different one is created.
If it was still the same object after changes it would be a shared resource between the 2 threads and will disrupt the state those threads men't to print.
When we do:
String string = new String("Ralph");
//This creates a reference called string that points to a sequence of
//characters in memory
This is the same as:
String string = "Ralph";
When we print both, we get the actual value of the string.
If we print any other object in Java, we get an address for that object.
My question is, is there any dereferencing that is taking place behind the scenes?
When you pass an object reference to the System.out.println() method, for
example, the object's toString() method is called, and the returned value of toString() is shown in the following example:
public class HardToRead {
public static void main (String [] args) {
HardToRead h = new HardToRead();
System.out.println(h);
}
}
Running the HardToRead class gives us the lovely and meaningful,
% java HardToRead
HardToRead#a47e0
Now,
Trying to read this output might motivate you to override the toString()
method in your classes, for example,
public class BobTest {
public static void main (String[] args) {
Bob f = new Bob("GoBobGo", 19);
System.out.println(f);
}
}
class Bob {
int shoeSize;
String nickName;
Bob(String nickName, int shoeSize) {
this.shoeSize = shoeSize;
this.nickName = nickName;
}
public String toString() {
return ("I am a Bob, but you can call me " + nickName +". My shoe size is " + shoeSize);
}
}
This ought to be a bit more readable:
% java BobTest
I am a Bob, but you can call me GoBobGo. My shoe size is 19
The class String is a special class in Java.
But it gets out printed the same way every other class does.
If we call System.out.println("Ralph") the function println takes that String and then displays it.
The class Objects toString() method is implemented, so it displays the hash code of the Object, by calling the hashCode() function. If you overwrite the toString() method, it will display something else.
If you take any object other than a String and give it to a method that takes a String (or in fact cast it to a String) java will call the toString()method of that Object, to convert it to a String.
So 'printing' always does the same thing, it's just implemented in different ways, using the toString() method.
new String("Ralph") copies the character data array of the literal string and stores it in the new String instance.
However, you only get the address of an object when you print it because printing uses the toString() method of that object. If that method is not implemented, the default implementation defined in Object is used, which returns the class name plus the hash code (that seems like an address if hashCode() is not implemented).
I believe the primary types are printed with auto dereferencingString, int, float, etc., while the objects other than primary types, only with de-referencing function object.toString() that are implemented on the object level.
I am not able to understand the behaviour (distinction) of equals method in String class and then overriding that equals method manually in custom class.
According to java, if we want two objects to be equal, then we should override equals method to check the equality among them. So, I made a Dog class and override equals method in that class. Further to check the equality among objects I used Set type collection as it does not allow duplicate. But I was confused to see the output. Here is my code:
import java.util.*;
class Dog{
int type;
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public boolean equals(Object o){
if((o instanceof Dog) && ((Dog)o).getType()==this.getType()){
return true;
}
else{
return false;
}
}
}
public class CheckEquality {
public static void main(String[] args) {
Dog d1=new Dog();
Dog d2=new Dog();
d1.setType(12);
d2.setType(12);
Set set=new HashSet();
if(set.add(d1)){
System.out.println("d1 added");
}
if(set.add(d2)){
System.out.println("d2 added");
}
String s1=new String("ad");
String s2=new String("ad");
//String s1="ad";
//String s2="ad";
Set set2=new HashSet();
if(set2.add(s1)){
System.out.println("s1 added");
}
if(set2.add(s2)){
System.out.println("s2 added");
}
}
}
output:
d1 added
d2 added
s1 added
what I expected:
d1 added
s1 added
can any one tell me why am I getting d2 addedd statement, when it can be seen that object with same type has already been added to Set.
While in contrary, String does NOT allow the statement s2 added. Why is it so?. Can anyone clear my doubts.
You are missing hashCode method.
This hash is used by other code when storing or manipulating the
instance – the values are intended to be evenly distributed for varied
inputs in order to use in clustering. This property is important to
the performance of hash tables and other data structures that store
objects in groups ("buckets") based on their computed hash values
You can use Objects class to generate hashcode.
public class Dog {
#Override
public int hashCode() {
return Objects.hash(type);
}
}
Because you have to override hashCode as well. Check the contract of Object#equals:
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.
Add this to your Dog class:
public class Dog {
#Override
public int hashCode() {
return this.type;
}
}
This is just a basic example. It would be better if type is a final field. From Object#hashCode:
Whenever it is invoked on the same object more than once during an execution of a Java 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.
The Set-implementation HashSet is expected to find values by using the hashCode. Your object does not provide a good hashCode but instead uses the version from Object. When implementing equals you should generally also always implement hashCode. It is simply a best practice.
In Java 8 you can provide a good and efficient hash by using the following code:
Objects.hash(value1, value2, value3);
If used properly the HashSet will work as expected. For the simple Dog-class the type can be returned but for more complex objects that contains more attributes the Objects.hash or similar is recommended.
If you does't override hashcode method there is collision issue while storing object in hashset. Hashset internally uses hashtable to key and value pair.
Since you must have to override the hashcode so that hashset found that same hashcode then it will internally call the equals the method.
#Override
public int hashCode() {
return type.hashcode();
}
I have some code where I try to use the HashSet.retainAll() function.
In the example code below, the HashSet contains the interface IPerson, but the equals functions in object Person is never reached. I have even tried to expose the equals function in the interface and several other things. I feel I have tried everything. How can I make retainAll() use my implemented equal function?
class Person implements IPerson {
private String name;
public Person(String name){
this.name = name;
}
#Override
public boolean equals(Object obj){
System.out.println("calling equals");
return super.equals(Object obj);
}
}
HashSet<IPerson> persons1 = new HashSet<IPerson>();
persons1.add(new Person("Jane"));
persons1.add(new Person("Joel"));
persons1.add(new Person("Joe"));
HashSet<IPerson> persons2 = new HashSet<IPerson>();
persons2.add(new Person("Jane"));
persons2.add(new Person("Joel"));
persons1.retainAll(persons2);
// expect sysout from Person.equals()
System.out.println(persons1.size());
// prints 0
you need to consider name to check equality and include it to compute hashCode also make sure you follow hashcode and equals contract
You need to override hashCode because the hashset uses the hashcode to find the right 'bucket' first and only calls equals after it finds something in it. That's why your equals method is never called. (if you don't override the hashcode method, it gives every new object a different hashcode, so even if you call new Person("name") twice with the same name they won't have the same hashcode)
I have this class:
private static class ClassA{
int id;
String name;
public ClassA(int id, String name){
this.id= id;
this.name = name;
}
#Override
public boolean equals(Object o) {
return ((ClassA)o).name.equals(this.name);
}
}
Why this main is printing 2 elements if I am overwriting the method equals in ClassA to compare only the name?
public static void main(String[] args){
ClassA myObject = new ClassA(1, "testing 1 2 3");
ClassA myObject2 = new ClassA(2, "testing 1 2 3");
Set<ClassA> set = new HashSet<ClassA>();
set.add(myObject);
set.add(myObject2);
System.out.println(set.size()); //will print 2, but I want to be 1!
}
If I look into the Set Java documentation:
A collection that contains no duplicate elements. More formally, sets contain no pair of elements e1 and e2 such that e1.equals(e2), and at most one null element. As implied by its name, this interface models the mathematical set abstraction.
So apparently I only have to override equals, however I heard that I have also to override the hashcode, but why?
They have different hashes because you didn't override hashCode. This means they were put in two different buckets in the HashSet, so they never got compared with equals in the first place.
I would add
public int hashCode() {
return name.hashCode();
}
Notice id isn't used in the hashCode because it isn't used in equals either.
(P.S. I'd also like to point out the irony of having an id that isn't used in equals. That's just funny. Usually it's the other way around: the id is the only thing in equals!)
Because you didn't override hashCode() as well.
programmers should take note that any class that overrides the Object.equals method must also override the Object.hashCode method in order to satisfy the general contract for the Object.hashCode method. In particular, c1.equals(c2) implies that c1.hashCode()==c2.hashCode().
http://download.oracle.com/javase/6/docs/api/java/util/Collection.html
And:
The general contract of hashCode is:
Whenever it is invoked on the same object more than once during an execution of a Java 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.
It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hashtables.
http://download.oracle.com/javase/6/docs/api/java/lang/Object.html#hashCode()