Java Class 'Object' Flashcards
Why is class ‘Object’ special in Java?
Every class in Java is directly or indirectly derived from the Object class. If a class does not extend any other class, it is a direct child class of the Object class. If a class extends other classes, it is indirectly derived. The Object class acts as the root of the inheritance hierarchy in any Java program. It also means that all methods of the Object class are available to all Java classes.
What’s the purpose of method ‘toString’?
‘toString’ method provides a String representation of an Object. If you print any object, the Java compiler will implicitly invoke the ‘toString’ method on the object.
The default method returns a String consisting of § The name of the class of which the object is an instance of; § '@' sign; § A Hexadecimal representation of the hashcode of the object ('Car@1eed6fc').
Calling ‘toString()’ method should be a concise but informative representation that is easy for a person to read. It is recommended that all subclasses override this method to produce other desired output, for example, the state of the object.
What’s the purpose of method ‘clone’?
The 'clone' method returns a new object that is a copy of the object the method is called on. Using the clone method is the easiest and most efficient way of copying objects and saves much effort. Please note that classes must implement the 'Cloneable' interface to support the default cloning behavior. By default, cloning in Java means creating a field by field copy. Suppose the class contains members of any class type. In that case, Java will copy only the object references. The member references in both the original and the cloned object refer to the same object (shallow copy/shallow clone).
What are the key considerations when overriding the ‘clone’ method?
When overriding the ‘clone’ method, we should keep in mind the difference between shallow and deep copy.
Shallow copy is the default implementation in Java. If you are not cloning all the object types (not primitives) in the overridden clone method, you are making a shallow copy. It means - member references in both the original and the cloned object will refer to the same object, the changes made in the clone will be visible in the original object.
Deep copy is the desired behavior in most cases. In the case of a deep copy, we create a clone independent of the original object and making changes in the cloned object should not affect the original object.
If the object we want to clone contains any Collection or Mutable object, we need to copy the state explicitly.
For example, out object has a List ‘list’ holding some values; we should explicitly create a new object for this List in the clone -> clone.list = new LinkedList(list).
What’s the purpose of method ‘hashCode’?
As much as is reasonably practical, the hashCode() method defined by class Object returns distinct integers for distinct objects. (This is typically implemented by converting the internal address of the object into an integer. JVM used hashCode() while saving objects into hashing related structures (HashMap, HashSet, HashTable, etc)). When using a hash table, these collections calculate the hash value for a given key using the hashCode() method and use it internally to store the data - so that access operations are much more efficient. Whenever hashCode() 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. It's not recommended to override the 'hashCode' method for mutable objects. His integer doesn't need to remain consistent from one execution of an application to another execution of the same application.
What’s the purpose of method ‘equals’?
The 'equals(Object object)' method returns a boolean indicating weather some other object is "equal to" this one ('true' if this object is the same as the object argument; 'false' otherwise). The equals method for class Object implements the most discriminating possible equivalence relation on objects. For any non-null reference values x and y, this method returns true if and only if x and y refer to the same object (x==y has the value 'true'). If two objects are equal, then their hash code must also be identical.
What are the key considerations when overriding the ‘equals’ method?
The default implementation of this method in the Object class checks if two object references x and y refer to the same object. It checks if x == y. This particular comparison is also know as “shallow comparison”. However, the classes providing their own implementations of the equals method ate supposed to perform a “deep comparison” by comparing the relevant data members. The implementation of the equals method should follow this contract:
A. It should be reflexive- the object must be equal to itself, which it would be at any given instance; unless the method is intentionally overridden to behave otherwise.
B. It should be symmetric - if object A is equal to object B, object B must be equal to object A.
C. It should be transitive - if object A is equal to object B, object B is equal to object C, object A must be equal to object C.
D. It should be consistent - if two objects are equal, they must remain equal as long as they are not modified.
E. For any null reference value, the method should return false. If the equals method is overridden, so should be the hashcode method to avoid undetermined and undesired behavior.
What’s the special relationship between ‘hashCode’ and ‘equals’ methods?
It is necessary to override the hashCode method whenever the equals method is overridden to maintain the general contract for the hashCode method, which states that equal objects must have identical hash codes. However, it is not required that objects that are not equal produce distinct hash codes.
What is a hash collision, and when should it be a concern?
A hash collision is a situation when two or more objects produce the same hash. This situation can occur because, according to equals and hashCode contract, two objects that are not equal in Java can have the same hash code. It can be a concern when working with different data structures that use hashing.
For example, in a HashMap, if two or more key objects produce the same final hash value, they will point to the same bucket location or array index because it’s the hash value of the key that determines the bucket where the object will be stored. If the hash codes of any two keys collide, their entries will still be stored in the same bucket. It can cause performance issues.
It is worth mentioning that since Java 8, the linked lists are dynamically replaced with balanced binary search trees in collision resolution after the number of collisions in a given bucket location exceed a certain threshold. This change offers a performance boost.