Equals() & HashCode() in Java

Equals(): The equals() method is used to compare two or more objects for equality. It is part of the java.lang.Object class but we can override the same in child class as well according to our requirement as all classes by default extend java.lang.Object class.

As per the method definition in object class, equality is checked on the basis of the object references i.e; Object obj1 is equal to Object obj2 if obj1 == obj2. Both objects should have same reference.

It is declared as below.

public boolean equals(Object obj) {

return (this == obj);

}

HashCode(): It is an integer representation of an object or you can say integer hash code value of the object. It is part of the java.lang.Object class but we can override the same in child class as well according to our requirement as all classes by default extend java.lang.Object class.

If 2 objects are equal that is if the obj1 == obj2, then hash code of both the objects would be same. But there are cases where hashCode for different objects are also same or you can say have the same hash code value. Hence hash code only can’t be used for equality check for objects.

So some important points which we make out now are :

  • If two objects are equal according to the equals method, then their hash code values should be equal too or you can say their hashcodes must be equal too.
  • If two objects are not equal according to the equals method, then their hashes can be equal or not equal.

If the object is altered i.e; a property value is changed then the hash code value for that object also changes.

How to declare an hashCode method?

public int hashCode(){

}

Overriding Equals() & HashCode():

Sometimes there may be a case in which there are 2 objects of the same class and class variables of both objects have equal values. So ideally they should be equal? But they are not since as we saw above, equals() method checks equality on the basis of memory reference (==).

If there comes a need to change the logic for equality check for a particular class then we would need to override the equals method in the child class.

But remember one important thing!!!

If we override equals(), then we would need to override hahsCode() as well because for equal objects, the hash code values should also be equal.

Class Employee
{
public String emp_name;
public String emp_email;

@Override
public int hashCode() {
	final int prime = 31;
	int result = 1;

	result = prime * result + (((emp_name == null) ? 0 : emp_name.hashCode()) + ((emp_email == null) ? 0 : emp_email.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;
	Employee other = (Employee) obj;
	if (emp_name != other.emp_name)
		return false;
	if (emp_name == null) {
		if (other.emp_name != null)
			return false;
	} else if (!emp_name.equals(other.emp_name))
		return false;
	if (emp_email == null) {
		if (other.emp_email != null)
			return false;
	} else if (!emp_email.equals(other.emp_email))
		return false;
	return true;
}

In the above example, Employee class has overriden equals and hashCode methods.

In equals, we are comparing the member variables which are emp_name and emp_email and returning equals as true or false.

Similarly hashCode is also over ridden to return same hash code value for equal objects.

Different ways to create Object in Java

  1. Using traditional way of Java new Operator – Employee emp = new Employee()
  2. Java Class. newInstance() method. – There is a class named Class :). It has a forNamemethod. It accepts the class name which we want to instantiate.On that we call the newInstance() method. For example,

class.forName(com.main.Employee).newInstance(); // it will create the object of employee class.

If you see above call, class.forName(com.main.Employee) actually loads the class and newInstance() method call creates the instance.

3. Using clone method – We can clone a class object by making the class implement the Cloneable interface and overriding the clone method of the Object class.

4.Deserialization – Another way is to De-serialize the object which is serialized in memory or in a file.

Object Cloning In Java

Suppose we want to create an object which is an exact copy of another object from the same class. In that case, we need to clone that object.

The object cloning is a way to create exact copy of an object. The clone() method which is defined in java.lang.Object class is used to create the clones of the objects. As you know all classes in java extend the Object class by default.

To facilitate cloning, the class to be cloned should implement the java.lang.cloneable interface. It is an marker interface. Like for serialization, serializable interface is implemented which is an marker interface. Such marker interfaces acts as an flag for the JVM to identify such classes with special capability to serialize and clone..

Syntax of the clone method :

protected Object clone() throws CloneNotSupportedException

Benefits of Cloning?

We don’t need to write huge lines of code to create a copy of an object. Suppose that actual object has 100 member variables with respective values,so in this case we need to write a copy for each variable in our own copy function.

We just implement the cloneable interface and call super class clone method to implement cloning for a class.

Drawbacks:

If we need to clone a child class object then we need to make sure that the parent class also implements the clone method or else super.clone() call would fail.

Consider below case.

Class Manager extends Employee implement java.lang.Cloneable {

public String name;

public String email;

public Object clone() throws CloneNotSupportedException{

return super.clone();//line 5

}

}

So here in line 5, we have overridden clone method from super class which is required. So super class should implement Cloneable interface as well and have overridden clone method.

Another drawback of cloning is that it does only shallow cloning and not deep cloning.

What is Shallow and Deep Cloning?

Shallow clone is “default implementation” in Java. In overridden clone method, if you are not cloning all the object types (not primitives), then you are making a shallow copy. So it means if there are member user class objects, after cloning the reference of those objects would be same in both actual as well as cloned object.

In the deep copy, we create a clone which is different from the actual object. So it means if there are member user class objects, after cloning the reference of those member objects would be different in actual and cloned object. That is those member objects are also cloned to have separate references or you can say copies.

Kindly check below.

@Override
protected Object clone() throws CloneNotSupportedException {
    Employee empClone = (Employee)super.clone();
    empClone.setDesignation((Designation)empClone.getDesignation().clone());   
    return empClone ;
}

Here the member object class which is Designation is cloned as well.

Serialization and Deserialization in Java

Serialization is the mechanism of converting the state of an object into a stream of bytes.

Deserialization is the exact opposite of that i.e; the byte stream is converted back to the object.

Why objects are serialized?

Sometimes it is important to capture the state of an object. For example in a mobile game if the game terminates abruptly and you reopen the game, it tells you to resume from where you let off. The point of resumption was may be maintained in an serialized object. When the game was restarted, the game programs de-serialized the object and got the resumption points.

Objects are serialized in memory or in a file. Since it is serialized as a stream of bytes, it is platform independent and can also be transmitted over the network.

This serialization of objects so so important.

Since the byte stream created is platform independent. So, the object serialized on one platform can be deserialized on a different platform.

How to make an Object serializable?

1)The object of the class which we want to serialize should implement the java.io.Serializable interface. It is an marker interface which means there is no method or member variables declared inside an interface. So the use of this interface is to mark that object or some special behavior which in our case is serialization.
2)Then to finally serialize the object in memory or in a file, we make use of the ObjectOutputStream class. The ObjectOutputStream class contains writeObject() method for serializing an Object. Kindly check below.

public final void writeObject(Object obj)
                       throws IOException

Similarly, the ObjectInputStream class contains readObject() method for deserializing an object.

public final Object readObject()
                  throws IOException,
               ClassNotFoundException

Which member are serialized?

When we try to serialize one object, the serialization process try to serialize all the fields (primitive and reference) with our class (except static and transient fields).

When a class implements the Serializable interface, all its sub classes become serializable as well. But when an object has a reference to another object, these objects must implement the Serializable interface separately. If our class is having even a single reference to a non Serializable class then JVM will throw NotSerializableException.

What is a serial version id?

It is an ID which is declared as a member variable inside a serializable class.

Suppose we have a class which is serialized to a file. Then there are some changes made to the class with one class variable removed. When we try to de-serialize the object, it would not serialize and additionally give an invalid class exception. Exception occurs because the class version has changed.

To resolve this, the Serialization runtime associates a version number with each Serializable class called a serial version id. So every object serialized of that class would have the same version number. So when that object is deserialized, it is successfully done and no exception occurs inspite of changes in the class structure.

A Serializable class can declare its own UID explicitly by declaring a field name.
It must be static, final and of type long.
It is declared as follows.

static final long serialVersionUID=70L;

What happens to the static and transient members?

As you read above, fields marked as static and transient are not serialized. So when de-serialization happens, transient fields are set as null(same applies for new fields which were added in class definition after object was serialized) and static field reads from JVM memory to get the latest value available there.

Let’s look at an example with the code.

import java.io.*; 
  
class SerialTest implements java.io.Serializable 
{ 
    //Member Variables
    private static final long serialversionUID = 
                                 149568898L;
    public String a; 
    public String b; 
  
    public SerialTest(String a, String b) 
    { 
        this.a = a; 
        this.b = b; 
    } 
  
} 
  
class MainTest 
{ 
    public static void main(String[] args) 
    {

        // Block for serialization 
    
        SerialTest ser = new SerialTest("James", "Gosling"); 
        String filename = "Serfile.ser"; 
          
        try
        {    
            FileOutputStream file = new FileOutputStream(filename); 
            ObjectOutputStream out = new ObjectOutputStream(file); 
              
            out.writeObject(ser); 
              
            out.close(); 
            file.close(); 
              
            System.out.println("Object has been serialized to a file"); 
  
        } 
          
        catch(IOException ex) 
        { 
            System.out.println("IOException occured"); 
        } 
  
  
        SerialTest ser2 = null; 
  
        // Block for Deserialization 
        try
        {    
            // Reading the object from a file 
            FileInputStream file = new FileInputStream(filename); 
            ObjectInputStream in = new ObjectInputStream(file); 
              
            ser2 = (SerialTest)in.readObject(); 
              
            in.close(); 
            file.close(); 
              
            System.out.println("Object has been deserialized from file"); 
            System.out.println("a = " + ser2.a); 
            System.out.println("b = " + ser2.b); 
        } 
          
        catch(IOException ex) 
        { 
            System.out.println("IOException occured while deserialization"); 
        } 
          
        catch(ClassNotFoundException ex) 
        { 
            System.out.println("ClassNotFoundException occured while deserialization"); 
        } 
  
    } 
} 
O/P:
Object has been serialized to file
Object has been deserialized from file
a = James
b = Gosling

Set Interface in Java

Src: Wiki Commons

Set is an collection which doesn’t contain duplicate elements unlike ArrayList which may contain dupes. So this makes set unique and different from other collections.

So Set is an interface which extends the Collection interface.

There are 3 implementations of Set:

1)HashSet : This is the best performing Set implementation. It doesn’t maintain the insertion order and neither it sorts the elements in ascending order.

2)TreeSet: This implementation of Set orders the elements according to their values.It stores the elements internally in a red black tree.

3)LinkedHashSet:It is implemented as a hash table with a linked list running through it, orders its elements based on the order in which they were inserted into the set (insertion-order).

Consider an Example. Suppose you want to remove duplicates from an ArrayList named as list. It contains a lot of dup strings. The same can be done easily by using a set as below.

Collection<String> uniqueList= new HashSet<String>(list);

The HashSet uniqueList will contain the unique elements.

Let’s see an example of elements getting inserted into an set collection.

import java.util.*;

public class SetExample {
    public static void main(String[] args) {
        Set<String> s1 = new HashSet<String>();
        for (String str : args)
               s1.add(str); //line 7
               System.out.println(s1.size() + " distinct words: " + s1);
    }
}

If you see line 7, there is an add method.

When the add method is called, it returns true or false. True on successful insertion and false when the element is already present i.e; a duplicate.

Let’s see some important methods of the Set Interface.

1) add( )

Adds an object to the collection.

2)clear( )

Removes all objects from the collection.

3)contains( )

Returns true if a specified object is an element within the collection.

4)isEmpty( )

Returns true if the collection has no elements.

5)iterator( )

Returns an Iterator object for the collection, which may be used to retrieve an object.

6)remove( )

Removes a specified object from the collection.

7)size( )

Returns the number of elements in the collection.

Now suppose, instead of a string there is an User Class Object like below.

Class Employee
{
   private string name = null;
   private string email = null;

   public void setName(String name)
   {
      this.name = name;
   }

   public String setEmail(String email)
   {
      this.email = email;
   }

   public static void main(String args[])
   {
      Employee e1 = new Employee();
      Employee e2 = new Employee();

      e1.setName("John");
      e2.setName("John");
      e1.setEmail("John@abc.com");
      e2.setEmail("John@abc.com");

      Set<Employee> s1 = new HashSet<Employee>();
      s1.add(e1);
      s1.add(e2);

      System.out.println("The size of the Set is "+s1.size());

   }
}

If you see the above example, we are inserting 2 objects into set. Both have the same values in their member variables but still both get inserted and output is printed as 2.Set allowed dupes here.

Why?

Because we didn’t override the equals and hashCode methods for the Employee class. The hashCode and reference of both the objects are different in spite of the class variable values being same. So set considers them different. To resolve this, we need to override the equals and hashCode methods for Employee class.

Operations on Set Interface:

The set interface allows the users to perform the basic mathematical operations on the set. Lets take and example . Let set1 = [1, 3, 2, 4, 5] and set2 = [1, 2,3,7,8]. Then the possible operations on the sets are:

1. Intersection: This operation returns all the common elements from the given two sets. For the above two sets, the intersection would be:

[1,3,2]

2. Union: This operation adds all the elements in one set with the other. The union for above case would be:

[1,2,3,4,5,7,8]

3. Difference: This operation removes all the values present in one set from the other set. The difference for above case would be:

[4,5]

Let’s look at the code.

import java.util.*;  
public class SetOperationExample  
{  
    public static void main(String args[])  
    {  
        Set<Integer> a = new HashSet<Integer>();  
        a.addAll(Arrays.asList(new Integer[] {1, 3, 2, 4, 5}));  

        Set<Integer> b = new HashSet<Integer>();  
        b.addAll(Arrays.asList(new Integer[] {1, 2, 3, 7, 8}));  
  
        // Union  
        Set<Integer> union = new HashSet<Integer>(a);  
        union.addAll(b);  
        System.out.print("Union of the two Set");  
        System.out.println(union);  
  
        // Intersection  
        Set<Integer> intersection = new HashSet<Integer>(a);  
        intersection.retainAll(b);  

        System.out.print("Intersection of the two Set");  
        System.out.println(intersection);  
  
        // Difference  
        Set<Integer> diff = new HashSet<Integer>(a);  
        diff.removeAll(b);  

        System.out.print("Difference of the two Set");  
        System.out.println(diff);  
    }  
}  

O/P:

[1,2,3,4,5,7,8]

[1,3,2]

[4,5]

Java Request Forward vs Redirect

When we are working with a java web application using jsp, we submit the request and get the response. But there are 2 ways in which request can be submitted.

1)Forward

2)Redirect

So what is the difference between the two?

The Forward method forwards a request from one servlet to another resource in a web application and this resource can be another servlet, JSP page, or HTML file. So in forward, the server or you can say the web container handles the forwarding of the request from one resource to another.

The redirect method on the other hand redirects the request to a different URL provided by us. The important point here is that the redirection is done by the browser and not the server. The URL can be part of the same web application hosted in the server or it can be complete different application.

The forward method is declared in the RequestDispatcher.

The SendRedirect( ) method is declared in HttPServletResponse and is used to redirect the client request to a different URL which can be available on a different server or same server. With a redirect, you can redirect the browser to a different application altogether.

When forward is called on requestdispather object we pass request and response object so our old request object is present on new resource which is going to process our request.

In case of SendRedirect call old request and response object is lost because it’s treated as new request by the browser.

Session is not lost in both forward and redirect!!!!

Dependency Injection and IOC in Spring?

Dependency injection is the ability of an object to supply dependencies of another object.

May be the above statement was a bouncer or many of you. So let us elaborate in detail what exactly is DI and IOC?

IOC stands for Inversion of Control. It is a mechanism in which we don’t explicitly create the objects. Spring IOC container uses the bean factory to create objects and store it into container. So here we are not explicitly creating objects using the new operator. Spring is creating the objects for us.

So by doing this we are achieving 3 things

1)Loose coupling.

2)Easier to Test code.

3)Less complexity.

So now the question is how spring creates objects for us?

When we explicitly create objects, we know the class names for which we need to create objects like below.

Vehicle v = new Vehicle();

But now, spring container will provide the vehicle object.

Spring Container maintains 2 configurations – One is xml based and another is annotation based.

XML Based Config – The container reads the configuration file and gets the list of objects or in spring language you say list of beans to be created.

Using Annotations – Spring @Component, @Service, @Repository and @Controller annotations are used for automatic bean detection using classpath scan in spring framework. These annotations are used before class declaration in each java file like below.

package com.sample;

@Component
Class Vehicle
{
int x;
int y;
.......
.......
}

Also we need to provide the ClassPath to the spring container in which it will start looking for these annotations so that it can create the objects.

ClassPath can be provided by defining an property for Component Scanning and corresponding class path value in the spring application context xml file.

or

It can be provided using @ComponentScan Annotation in the main class. With Spring, we use the @ComponentScan annotation along with @Configuration annotation to specify the packages that we want to be scanned. @ComponentScan without arguments tells Spring to scan the current package and all of its sub-packages.

Simply put – @ComponentScan tells Spring in which packages you have annotated classes which should be managed by Spring.

@ComponentScan(basePackages = "com.sample")
@Configuration
public class Application {

    private static final Logger logger = LoggerFactory.getLogger(Application.class);

    public static void main(String[] args) {

        var ctx = new AnnotationConfigApplicationContext(Application.class);
        Vehicle v = (Vehicle) ctx.getBean("Vehicle");
        ctx.close();
    }
}

The constructor of the AnnotationConfigApplicationContext class takes multiple arguments of the @Configuration class. That means all configuration could be passed at once during the creation of the context.

Dependency Injection Benefits

  • Reduced Dependencies.
  • Reduced Dependency Carrying.
  • More Reusable Code.
  • More Testable Code.
  • More Readable Code.

Basics of Database Sharding?

Suppose there is a huge database on a single server or you can say a single node.

If the data is huge in a single table, it becomes a case for horizontal partitioning. Horizontal partitioning means dividing a single table into multiple tables by splitting it.

In database sharding, table is distributed among multiple nodes (database servers) on the basis of a column. That column should preferably be an primary key.

A Hash function is applied to the column and the rows are distributed across multiple nodes. For example the column is ID ranging from 1 to 500.So if there 4 nodes, then 125 rows would b distributed into each of the 4 nodes. Provided the hash function is good 🙂

The hash function should be good, such that there is even distribution in all nodes. There should be no case of one node handling or containing way more data than other nodes. Efficiency is achieved through this.

Consider an location based app. There is an address table having city info. Using city column, shards can be created. Like for New York, we can have a dedicated shard 1, Mumbai goes to Shard 2, Moscow goes to Shard 3. Hash function should do the job.

But consider a case, where the Mumbai Shard grows with increasing data and increasing requests, an multi level cluster can be created for that shard.

The advantage of multiple shards is that if one cluster shuts down, others can keep on working.

But there is an issue with sharding. Most RDBMS systems like SQL Server, Oracle etc

don’t support automatic sharding. It has to be manual harding. So it increases development effort.

Tips to Avoid Null Pointer Exception in Java

Null pointer exception takes place when we try to do an operation on a null object. Null pointer Exception is something which troubles every java developer on a regular basis.

But there are ways in which we can avoid it to the best. Let’s look at it one by one.

1)Having null checks.

String test = null;

if (test != null)
{
    String test2 = test.substring(0,1); \\line 4
}

If the null check of test != null was not there, then it would had resulted in null pointer exception since we are doing on operation on line 4 on the null string object by calling substring method.

2)Using ternary: We can rewrite the above null check using ternary operator.

String test = null;
String test2 = test!=null?test.substring(0,1):""; \\line 4

So here we see that in a single line we can do a null check. If test is not null then apply substring or else return blank “”

3)If there is an integer which is null and we want to convert it into a string then we use valueOf method from the string class to do the same.

Integer num = null;

String num2 = String.valueOf(num); // No null pointer exception
String num3 = Integer.toString(); // Null pointer exception

If you see above, using toString() directly on Integer object would had caused null pointer exception.

4)If we are using hashMap to get value against a particular key, it is always better to use containsKey method. Let’s see how.


HashMap testMap = new HashMap();
testMap.put("name","John");
testMap.put("age","35");

String gender = testMap.get("gender"); \\ we get gender as null since there is no key as gender as seen above.

String val = gender.substring(0,1); //Fails with null pointer exception

//To resolve it let's do below

if (testMap.containsKey("gender"))
{
   String val = gender.substring(0,1);
}


5) Using instanceOf keyword.

String name =  null;
if (name instanceOf String)
{
    String val = name.substring(0,1);
}

If condition returns true or false. If it is null then it returns false so it doesn’t go inside if block.

6) Using Optional Class:

Introduced in Java 8, Optional is a container object used to contain not-null objects. Optional object is used to represent null with absent value. This class has various utility methods to facilitate code to handle values as ‘available’ or ‘not available’ instead of checking null values

String value1 = null;
Optional<Integer> a = Optional.ofNullable(value1);

7)If the source of the values is database and we are processing those values in java, then it is always better to check the database table columns. If we can enforce null or not null constraints there. Columns which should not be null should be created with not null constraints. Due to this, we can minimize our scope of null checks at java side.

Abstract Class and Interface in Java

What is an Abstract class?

Abstract class is an class which may or may not have an abstract method. Also an abstract class cannot be instantiated.

public abstract class AbstractClassExample

{

public abstract int getNum();

public int divideBy2(int x)

{

return x/2;

}

}

public class ChildAbstractExample extends AbstractClassExample

{

public int getNum()

{

int y = 5;

return y;

}

public static void main(String args[])
{

int x,y;
ChildAbstractExample cae = new ChildAbstractExample();

x = cae.divideBy2(100);

y = cae.getNum();

System.out.println(x);

System.out.println(y);
}

}

O/P:

50

5

If you see the above method, there is an abstract method and a non abstract method.

Whenever an method is declared as abstract, then the child class which inherits the abstract class must provide the implementation.

The non abstract method divideBy2() divides any number passed as a parameter by 2 and provides the o/p. The method would be available to all child classes which inherits the parent abstract class.

When to use Abstract Class?

a)When you want to share code among several closely related classes. Like in the above case, if several different classes want to use divideBy2() method then can extend the abstract class. Also with abstract class, we avoid instantiation of it so the method divideBy2() can only be called through child classes. So abstract classes can only be used through child classes.

b)You expect that classes that extend your abstract class have many common methods or fields or require access modifiers other than public.

What is an Interface?

An interface is just the declaration of methods of an object; it’s not the implementation. In an interface, we define what kind of operation an object can perform. These operations are defined by the classes that implement the interface. Interfaces form a contract between the class and the outside world, and this contract is enforced at build time by the compiler.

public interface InterfaceExample

{

int getX();

int getY();

}

All the methods inside an interface are by default public and abstract and doesn’t have any implementation. So any class which implements the interface must override all the methods declared inside interface. This is the contract which we spoke about.

Along with abstract methods, an interface may also contain constants, default methods, static methods, and nested types. Method bodies exist only for default methods and static methods.

Consider using interfaces if any of these statements apply to your situation:

  1. You expect that unrelated classes would implement your interface.
  2. You want to specify the behavior of a particular data type, but not concerned about who implements its behavior.
  3. You want to take advantage of multiple inheritances.

Let’s see an example below:

interface Animal {
   public void eat();
   public void travel();
}

public class MammalInt implements Animal 
{    
    public void eat() 
    {       
          System.out.println("Mammal eats");    
    }    
    public void travel() 
    {       
          System.out.println("Mammal travels");    
    }     
    public int noOfLegs() 
    {       
          return 0;    
    }
    
    public static void main(String args[]) 
    {       
       MammalInt m = new MammalInt();       
       m.eat();       
       m.travel();    
    } 
}