Generics

Why Generics?

  • To minimize Runtime issues during development of a Project. These issues are hidden and takes good amount of time to find and fix the issues
  • Type-safe Programming which improves accuracy in coding.

Different ways of Using Generics

  • Generic Class or Interface
    • Multi-type Parameters
  • Generic Methods
  • Wild Cards usage

Generic Class or Interface

Purpose of creating Generic class or Interface is to maintain specific parameterized object and manipulate it within Class’s boundary. Syntax of Generic class is:

class GenericClass<T1, T2… Tn> {
…
}

In above systax T1, T2 are the types of parameters which can be used anywhere within the class. You can specify ‘n’ number of parameters to define a Generic type class. Here is an example of non-generic and generic type class

Generic Class Non-Generic Class
public class Foo<O> { 
    private O o; 
    public Foo(O o){ 
       this.o = o; 
    } 

    public void set(O o) {
        this.o = o;
    } 

    public O get() { 
         return o; 
    } 
}
public class Foo { 
      private Object obj; 
      public Foo(Object obj){ 
            this.obj = obj; 
      } 

      public void set(Object obj) { 
            this.obj = obj; 
      } 

      public Object get() { 
            return obj; 
      } 
}

In above example non-generic and generic classes are shown to use any type of Object. Non-generic class will need type casting every time whenever it’s get() method is invoked but that’s not the case with Generic class.

Foo instance = new Foo(“This is String object”);     //non-generic object
Foo<String> instance = new Foo<String>(“Only String object”); //generic object

Now both the above statements look similar except generic <String> declaration.

Foo<String> instance = new Foo<String>(123); //Compile time error

You can’t pass another type of object in that class. In declaration part, String class is used as Generic type.

Multi-type Parameters

Multi-type parameters allows developers to send multiple types of Objects at Class level. Multiple parameters allows a developer to provide flexibility at interface level. Below example shows Generic and Specific usage of Generics also.

First Scenario

/**
 * Authenticator is the interface which allows implementation classes to provide
 * various authentication schemes.
 * 
 * @author Arun Sharma
 *
 * @param  input parameter as Id
 * @param

input parameter as password */ public interface Authenticator<T, P> { boolean authenticate(T id, P password); }

/**
 * UserAuthentication will always accept two String type parameters.
 * If 
 * @author Arun Sharma
 *
 */
public class UserAuthentication implements Authenticator<String, String>{

	public boolean authenticate(String id, String password) {
		if(id != null && password != null){
			return id.equals("arun") && password.equals("password");
		}
		return false;
	}	
}
/**
 * SystemAuthentication will always accept one Long and one String type parameters 
 * as System Id and password.
 * @author Arun Sharma
 *
 */
public class SystemAuthentication implements Authenticator<Long, String>{
	
	public boolean authenticate(Long id, String password) {
		return id == 1 && password.equals("password");
	}
}

In above examples as you can see there are two implementation classes of Authenticator interface. SystemAuthentication class can be initialized with only Long, String value whereas UserAuthentication class will use String, String.

/*
 * 'UserAuthentication' object only receives two String parameters
 * as these parameters were defined at Class while implementing Authentication
 * interface
 */
Authenticator<String, String> auth = new UserAuthentication();
boolean authenticated = auth.authenticate("arun", "password");
System.out.println(authenticated);
		
/*
 * whereas 'SystemAuthentication' accepts Long and String parameters.  
 */
Authenticator<Long, String> auth1 = new SystemAuthentication();
authenticated = auth1.authenticate(1L, "password");
System.out.println(authenticated);

Second Scenario

Above example explains how you can stick Generic feature to the specific class for same interface behavior. Now if you need to make Authenticator interface and its implementation classes more Generic, just replace <String, String> to <T, P> or <Long, String>.

public class SystemAuthentication<T, P> implements Authenticator<T, P> {
       public boolean authenticate(T id, P password) {
          return id.equals(1) && password.equals("password");
       }
}

public class UserAuthentication<T, P> implements Authenticator<T, P>{
   public boolean authenticate(T id, P password) {
        if(id != null && password != null){
           return id.equals("arun") && password.equals("password");
        }
        return false;
    }
}


public static void main(String[] args) {
   Authenticator<String, String> auth = new UserAuthentication<String, String>();
   boolean authenticated = auth.authenticate("arun", "password");
   System.out.println(authenticated);
	
   Authenticator<Integer, String> auth1 = new SystemAuthentication<Integer, String>();
   authenticated = auth1.authenticate(1, "password");
   System.out.println(authenticated);		
}

One comment

  1. Staysha

    You’ve maeangd a first class post

Leave a Reply

Your email address will not be published. Required fields are marked *