Wednesday, 31 December 2014

Difference Between Iterator And ListIterator In Java

Iterator and ListIterator are two interfaces in Java collection framework which are used to traverse the collections. Although ListIterator extends Iterator, there are some differences in the way they traverse the collections.

1) Using Iterator, you can traverse List, Set and Queue type of objects. But using ListIterator, you can traverse only List objects. In Set and Queue types, there is no method to get the ListIterator object. But, In List types, there is a method called listIterator() which returns ListIterator object.

class IteratorAndListIterator
{
    public static void main(String[] args)
    {
        List list = new ArrayList();

        list.add("ONE");

        list.add("TWO");

        list.add("THREE");

        //Traversing list elements using Iterator
        Iterator iterator1 = list.iterator();

        while (iterator1.hasNext())
        {
            System.out.println(iterator1.next());
        }

        Queue queue = new PriorityQueue(list);

        //Traversing queue elements using Iterator
        Iterator iterator2 = queue.iterator();

        while (iterator2.hasNext())
        {
            System.out.println(iterator2.next());
        }

        Set set = new HashSet(list);

        //Traversing set elements using Iterator
        Iterator iterator3 = set.iterator();

        while (iterator3.hasNext())
        {
            System.out.println(iterator3.next());
        }

        //Traversing list elements using ListIterator
        ListIterator listIterator1 = list.listIterator();

        while (listIterator1.hasNext())
        {
            System.out.println(listIterator1.next());
        }

        //Traversing queue and set elements using ListIterator is not possible

        ListIterator listIterator2 = queue.listIterator();    //Compile time error, there is no such method in Queue

        ListIterator listIterator3 = set.listIterator();     //Compile time error, there is no such method in Set
    }
}

2) Using Iterator, we can traverse the elements only in forward direction. But, using ListIterator you can traverse the elements in both the directions – forward and backward. ListIterator has those methods to support the traversing of elements in both the directions.

Iterator Methods :

boolean hasNext() –> Checks whether collection has more elements.

E next()  –> Returns the next element in the collection.

void remove()  –> Removes the current element in the collection i.e element returned by next().

ListIterator Methods :

boolean hasNext() –> Checks whether the list has more elements when traversing the list in forward direction.

boolean hasPrevious() –> Checks whether list has more elements when traversing the list in backward direction.

E next()  –> Returns the next element in the list and moves the cursor forward.

E previous()  –> Returns the previous element in the list and moves the cursor backward.

int nextIndex() –> Returns index of the next element in the list.

int previousIndex() –> Returns index of the previous element in the list.

void remove()  –> Removes the current element in the collection i.e element returned by next() or previous().

void set(E e) –> Replaces the current element i.e element returned by next() or previous() with the specified element.

void add(E e) –> Inserts the specified element in the list.

class IteratorAndListIterator
{
    public static void main(String[] args)
    {
        List<String> list = new ArrayList<String>();

        list.add("FIRST");

        list.add("SECOND");

        list.add("THIRD");

        //Traversing list elements in forward direction using Iterator

        Iterator iterator = list.iterator();

        while (iterator.hasNext())
        {
            System.out.println(iterator.next());
        }

        //        OUTPUT :
        //        FIRST
        //        SECOND
        //        THIRD

        //Traversing list elements in forward direction using ListIterator

        ListIterator listIterator = list.listIterator();

        while (listIterator.hasNext())
        {
            System.out.println(listIterator.next());
        }

        //        OUTPUT :
        //        FIRST
        //        SECOND
        //        THIRD

        //Traversing list elements in backward direction using ListIterator

        while (listIterator.hasPrevious())
        {
            System.out.println(listIterator.previous());
        }

        //        OUTPUT :
        //        THIRD
        //        SECOND
        //        FIRST
    }
}

3) Using ListIterator, you can obtain index of next and previous elements. But, it is not possible with Iterator interface.

import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;

class IteratorAndListIterator
{
    public static void main(String[] args)
    {
        List<String> list = new ArrayList<String>();

        list.add("FIRST");

        list.add("SECOND");

        list.add("THIRD");

        ListIterator listIterator = list.listIterator();

        while (listIterator.hasNext())
        {
            //Getting index of next element

            System.out.println(listIterator.nextIndex()+" : "+listIterator.next());
        }

        //        OUTPUT :
        //        0 : FIRST
        //        1 : SECOND
        //        2 : THIRD

        while (listIterator.hasPrevious())
        {
            //Getting index of previous element

            System.out.println(listIterator.previousIndex()+" : "+listIterator.previous());
        }

        //        OUTPUT :
        //        2 : THIRD
        //        1 : SECOND
        //        0 : FIRST
    }
}

4) Using ListIterator, you can perform modifications(insert, replace, remove) on the list. But, using Iterator you can only remove the elements from the collection.

class IteratorAndListIterator
{
    public static void main(String[] args)
    {
        List<String> list = new ArrayList<String>();

        list.add("FIRST");

        list.add("SECOND");

        list.add("THIRD");

        ListIterator<String> listIterator = list.listIterator();

        System.out.println(list);       //Output :    [FIRST, SECOND, THIRD]

        while (listIterator.hasNext())
        {
            listIterator.next();

            //Modifying an element returned by next()
            listIterator.set("MODIFIED");
        }

        System.out.println(list);       //Output :    [MODIFIED, MODIFIED, MODIFIED]

        Iterator<String> iterator = list.iterator();

        while (iterator.hasNext())
        {
            iterator.next();

            //Removing an element
            iterator.remove();
        }

        System.out.println(list);    //Output : []
    }
}

5) Using ListIterator, you can iterate a list from the specified index. It is not possible with Iterator.

class IteratorAndListIterator
{
    public static void main(String[] args)
    {
        List<String> list = new ArrayList<String>();

        list.add("FIRST");

        list.add("SECOND");

        list.add("THIRD");

        list.add("FOURTH");

        list.add("FIFTH");

        //Iterating list from index 2 using ListIterator

        ListIterator<String> listIterator = list.listIterator(2);

        while (listIterator.hasNext())
        {
            System.out.println(listIterator.next());
        }

        //        OUTPUT :
        //        THIRD
        //        FOURTH
        //        FIFTH
    }
}

Different Ways Of Iterating An ArrayList In Java


You can iterate a given ArrayList in 4 different ways. They are,

a) Iteration Using Normal for loop.

b) Iteration Using Iterator Object.

c) Iteration Using ListIterator Object.

d) Iteration Using Enhanced for loop.

Below is the detail description of all of the above methods.

Iteration Using Normal for loop :

This method is useful when you also need index of the elements along with the elements itself. Using this method, you can also iterate a part of an ArrayList. Here is the template for this method.

for (int i = 0; i < list.size(); i++)
{
        type_of_element element = list.get(i);
}

Iteration Using Iterator :

This method is useful when you don’t want index of an element, but you want to remove the elements as you iterate through an ArrayList.

while (iterator.hasNext())
{
    System.out.println(iterator.next());

    //Removing an element from ArrayList
    iterator.remove();
}

Iteration Using ListIterator :

If you want to iterate the list in both the directions – forward and backward, then use the ListIterator method. One more advantage of this method is, you can start iteration from a specific element in an ArrayList.

while (listIterator.hasNext() or listIterator.hasPrevious())
{
    System.out.println(listIterator.next());

        System.out.println(listIterator.previous());
}


Iteration Using Enhanced for loop :

This method is useful when you don’t need indexes of elements and you just want to access the elements without removing them or modifying them (it is the most common case). This method is also short and very easy to write.

for (type_of_element element : list)
{
    System.out.println(element);
}

Here is the program which implements all of the above four methods.

class ArrayListIteration
{
    public static void main(String[] args)
    {
        ArrayList<String> list = new ArrayList<String>();

        list.add("FIRST");

        list.add("SECOND");

        list.add("THIRD");

        list.add("FOURTH");

        list.add("FIFTH");

        //1. Using for loop

        for (int i = 0; i < list.size(); i++)
        {
            System.out.println(list.get(i));
        }

        //2. Using Iterator

        Iterator<String> it = list.iterator();

        while (it.hasNext())
        {
            System.out.println(it.next());

            //Removing an element from list
            it.remove();
        }

        //3. Using ListIterator

        ListIterator<String> listIt = list.listIterator();

        while (listIt.hasNext())
        {
            System.out.println(listIt.next());
        }

        //4. Using enhanced for loop

        for (String element : list)
        {
            System.out.println(element);
        }
    }
}

Java Programming Examples On ArrayList – 2


7) How do you get the position of a particular element in an ArrayList?

We can use indexOf() and lastIndexOf() methods to find out the position of a given element in an ArrayList. indexOf() method returns index of first occurrence of a specified element where as lastIndexOf() method returns index of last occurrence of a specified element in an ArrayList. If element is not found, they will return -1.

public class MainClass
{
    public static void main(String[] args)
    {
        ArrayList<String> list = new ArrayList<String>();

        list.add("JAVA");

        list.add("J2EE");

        list.add("JSP");

        list.add("JAVA");

        list.add("SERVLETS");

        list.add("JAVA");

        list.add("STRUTS");

        System.out.println(list);     //Output : [JAVA, J2EE, JSP, JAVA, SERVLETS, JAVA, STRUTS]

        //Getting the index of first occurrence of "JAVA"

        System.out.println(list.indexOf("JAVA"));     //Output : 0

        //Getting the index of last occurrence of "JAVA"

        System.out.println(list.lastIndexOf("JAVA"));    //Output : 5
    }
}

8) How do you convert an ArrayList to Array?

Using toArray() method of ArrayList class. toArray() method returns an array containing all elements of the ArrayList. This method acts as a bridge between normal arrays and collection framework in java.

public class MainClass
{
    public static void main(String[] args)
    {
        ArrayList<String> list = new ArrayList<String>();

        list.add("JAVA");

        list.add("J2EE");

        list.add("JSP");

        list.add("SERVLETS");

        list.add("STRUTS");

        System.out.println(list);      //Output : [JAVA, J2EE, JSP, SERVLETS, STRUTS]

        //getting an array containing all elements of the list.

        Object[] array = list.toArray();

        //Printing the elements of the returned array.

        for (Object object : array)
        {
            System.out.println(object);
        }

//        Output :

//        JAVA
//        J2EE
//        JSP
//        SERVLETS
//        STRUTS
    }
}

9) How do you retrieve an element from a particular position of an ArrayList?

get() method returns an element from a specified position of an ArrayList. This method takes index of the element as an argument.

public class MainClass
{
    public static void main(String[] args)
    {
        ArrayList<Integer> list = new ArrayList<Integer>();

        list.add(111);

        list.add(222);

        list.add(333);

        list.add(444);

        System.out.println(list);     //Output : [111, 222, 333, 444]

        //Getting element at index 3

        System.out.println(list.get(3));    //Output : 444

        //Getting element at index 1

        System.out.println(list.get(1));    //Output : 222
    }
}

10) How do you replace a particular element in an ArrayList with the given element?

set() method replaces a particular element in an Arraylist with the given element. This method takes two arguments. One is the index of the element to be replaced and another one is the element to be placed at that position.

public class MainClass
{
    public static void main(String[] args)
    {
        ArrayList<Integer> list = new ArrayList<Integer>();

        list.add(111);

        list.add(222);

        list.add(333);

        list.add(444);

        System.out.println(list);     //Output : [111, 222, 333, 444]

        //Replacing the element at index 1 with '000'

        list.set(1, 000);

        //Replacing the element at index 3 with '000'

        list.set(3, 000);

        System.out.println(list);   //Output : [111, 0, 333, 0]
    }
}

11) How do you append an element at the end of an ArrayList?

add() method appends an element at the end of an ArrayList.

public class MainClass
{
    public static void main(String[] args)
    {
        ArrayList<String> list = new ArrayList<String>();

        list.add("ONE");

        list.add("TWO");

        list.add("THREE");

        list.add("FOUR");

        System.out.println(list);     //Output : [ONE, TWO, THREE, FOUR]
    }
}


12) How do you insert an element at a particular position of an ArrayList?

add() method which takes index and an element as arguments can be used to insert an element at a particular position of an ArrayList. The elements at the right side of that position are shifted one position right i.e indices of right side elements of that position are increased by 1.

public class MainClass
{
    public static void main(String[] args)
    {
        ArrayList<String> list = new ArrayList<String>();

        list.add("ONE");

        list.add("TWO");

        list.add("THREE");

        list.add("FOUR");

        System.out.println(list);     //Output : [ONE, TWO, THREE, FOUR]

        //Inserting "AAA" at index 1

        list.add(1, "AAA");

        //Inserting "BBB" at index 3

        list.add(3, "BBB");

        System.out.println(list);    //Output : [ONE, AAA, TWO, BBB, THREE, FOUR]
    }
}

13) How do you remove an element from a particular position of an ArrayList?

remove() method which takes int type as an argument is used to remove an element from a particular position of an ArrayList.

public class MainClass
{
    public static void main(String[] args)
    {
        ArrayList<String> list = new ArrayList<String>();

        list.add("AAA");

        list.add("BBB");

        list.add("ccc");

        list.add("DDD");

        list.add("e");

        System.out.println(list);     //Output : [AAA, BBB, ccc, DDD, e]

        //Removing an element from position 2

        list.remove(2);

        System.out.println(list);    //Output : [AAA, BBB, DDD, e]

        //Removing an element from position 3

        list.remove(3);

        System.out.println(list);   //Output : [AAA, BBB, DDD]
    }
}

14) How do you remove the given element from an ArrayList?

remove(Object obj) method removes the first occurrence of the specified element ‘obj‘. If that element doesn’t exist, ArrayList will be unchanged.

public class MainClass
{
    public static void main(String[] args)
    {
        ArrayList<String> list = new ArrayList<String>();

        list.add("AAA");

        list.add("BBB");

        list.add("AAA");

        list.add("CCC");

        list.add("BBB");

        System.out.println(list);     //Output : [AAA, BBB, AAA, CCC, BBB]

        //Removing first occurrence of "AAA"

        list.remove("AAA");

        System.out.println(list);    //Output : [BBB, AAA, CCC, BBB]

        //Removing first occurrence of "BBB"

        list.remove("BBB");

        System.out.println(list);   //Output : [AAA, CCC, BBB]
    }
}

15) How do you remove all elements of an ArrayList at a time?

clear() method removes all elements of an ArrayList. ArrayList will be empty after this method is executed.

public class MainClass
{
    public static void main(String[] args)
    {
        ArrayList<String> list = new ArrayList<String>();

        list.add("AAA");

        list.add("BBB");

        list.add("AAA");

        list.add("CCC");

        list.add("BBB");

        System.out.println(list);     //Output : [AAA, BBB, AAA, CCC, BBB]

        //Removing all elements of the list

        list.clear();

        System.out.println(list);    //Output : []
    }
}

16) How do you retrieve a portion of an ArrayList?

Using subList() method of ArrayList, we can retrieve a portion of an ArrayList. subList() method returns a view of a portion of an ArrayList in the given range. The returned subList is backed by original ArrayList. That means any changes made to subList will be reflected in original ArrayList or Vice-Versa.

public class MainClass
{
    public static void main(String[] args)
    {
        ArrayList<Integer> list = new ArrayList<Integer>();

        list.add(111);

        list.add(222);

        list.add(333);

        list.add(444);

        list.add(555);

        list.add(666);

        System.out.println(list);     //Output : [111, 222, 333, 444, 555, 666]

        //Retrieving a SubList

        List<Integer> subList = list.subList(1, 4);

        System.out.println(subList);    //Output : [222, 333, 444]

        //Modifying the list

        list.set(2, 000);

        //Changes will be reflected in subList

        System.out.println(subList);    //Output : [222, 0, 444]

        //Modifying the subList

        subList.set(2, 000);

        //Changes will be reflected in list

        System.out.println(list);    //Output : [111, 222, 0, 0, 555, 666]
    }
}

Java Programming Examples On ArrayList – 1


1) Explain the different ways of constructing an ArrayList?

ArrayList can be created in 3 ways.

a) ArrayList() —> It creates an empty ArrayList with initial capacity of 10.

b) ArrayList(int initialCapacity) —> It creates an empty ArrayList with supplied initial capacity.

c) ArrayList(Collection c) —> It creates an ArrayList containing the elements of the supplied collection.

public class MainClass
{
    public static void main(String[] args)
    {
        ArrayList<Integer> list1 = new ArrayList<Integer>();            //First Method

        ArrayList<String> list2 = new ArrayList<String>(20);         //Second Method

        ArrayList<Integer> list3 = new ArrayList<Integer>(list1);      //Third Method
    }
}

2) How do you increase the current capacity of an ArrayList?

ensureCapacity() method can be used to increase the current capacity of an ArrayList. However, capacity of an ArrayList is automatically increased when we try to add more elements than the current capacity. To manually increase the current capacity, ensureCapacity() method is used.

public class MainClass
{
    public static void main(String[] args)
    {
        ArrayList<String> list = new ArrayList<String>();

        //Now 'list' can hold 10 elements (Default Initial Capacity)

        list.ensureCapacity(20);

        //Now 'list' can hold 20 elements.
    }
}

3) How do you decrease the current capacity of an ArrayList to the current size?

trimToSize() method is used to trim the capacity of arrayList to the current size of ArrayList. Developers use this method to minimize the storage area of an ArrayList.

public class MainClass
{
    public static void main(String[] args)
    {
        ArrayList<String> list = new ArrayList<String>();

        //Now 'list' can hold 10 elements (Default Initial Capacity)

        list.ensureCapacity(20);

        //Now 'list' can hold 20 elements.

        list.add("ONE");

        list.add("TWO");

        list.add("THREE");

        list.add("FOUR");

        //reducing the current capacity to current size of an ArrayList.

        list.trimToSize();
    }
}

4) How do you find the number of elements present in an ArrayList?

Using size() method. size() method returns number of elements present in an ArrayList.


public class MainClass
{
    public static void main(String[] args)
    {
        ArrayList<Double> list = new ArrayList<Double>();

        list.add(1.1);

        list.add(2.2);

        list.add(3.3);

        list.add(4.4);

        list.add(5.5);

        System.out.println(list);     //Output : [1.1, 2.2, 3.3, 4.4, 5.5]

        System.out.println("Size Of ArrayList = "+list.size());   //Output : Size Of ArrayList = 5
    }
}

5) How do you find out whether the given ArrayList is empty or not?

isEmpty() method of ArrayList can be used to check whether the given ArrayList is empty or not. This method returns true if an ArrayList contains no elements otherwise returns false.

public class MainClass
{
    public static void main(String[] args)
    {
        ArrayList<Double> list = new ArrayList<Double>();

        System.out.println(list.isEmpty());    //Output : true
    }
}

Note : You can also use size() method to check whether the given ArrayList is empty or not. size() method returns ‘0’ if an ArrayList is empty.

6) How do you check whether the given element is present in an ArrayList or not?

Using contains() method of ArrayList, we can examine whether the ArrayList contains the given element or not. This method returns true if ArrayList has that element otherwise returns false.


public class MainClass
{
    public static void main(String[] args)
    {
        ArrayList<Double> list = new ArrayList<Double>();

        list.add(1.1);

        list.add(11.11);

        list.add(111.111);

        list.add(1111.1111);

        //Checking whether list conatins '111.1111'

        System.out.println(list.contains(111.1111));    //Output : false
    }
}

Tuesday, 24 June 2014

Java Generics Example


Generics was first introduced in JDK 5 version. Now Generics is one of the most profound feature of Java Programming.Generics provide facility to write algorithm independent of any specific type of data. It also provide type-safety. Using Generics, it is possible to create a single class or method that automatically works with all type of data(Integer,String,Float,Double etc).

Generics was provide compile-time type checking and removing risk of ClassCastException that was common while working with collection classes. The whole collection framework was re-written to use generics for type-safety. Let’s see how generics help us using collection classes safely.

List list = new ArrayList();
          list.add("Sachin");
          list.add(new Integer(5)); // OK
          for (Object obj : list) {
              String str = (String) obj; // type casting leading to
                                                // ClassCastException at runtime

          }

Above code compiles fine but throws ClassCastException at runtime because we are trying to cast Object in the list to String whereas one of the element is of type Integer. After Java 5, we use collection classes like below.

List<String> list1 = new ArrayList<String>(); // java 7 ? List<String> list1 = new ArrayList<>();
          list1.add("Sachin");
          //list1.add(new Integer(5)); //compiler error

          for(String str : list1){
               //no type casting needed, avoids ClassCastException
          }


Notice that at the time of list creation, we have specified that the type of elements in the list will be String. So if we try to add any other type of object in the list, the program will throw compile time error. Also notice that in for loop, we don’t need type casting of the element in the list, hence removing the ClassCastException at runtime.

Generics with Class and Interfaces

We can define our own classes and interfaces with generics type. A generic type is a class or interface that is parameterized over types. We use angle brackets (<>) to specify the type parameter.

package com.naresh.generics;

public class GenericsTypeOld {

     private Object t;

     public Object get() {
          return t;
     }

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

        public static void main(String mnb[]){
          GenericsTypeOld type = new GenericsTypeOld();
          type.set("Pawan Kalyan");
          String str = (String) type.get(); //type casting, error prone and can cause ClassCastException
     }

}

Notice that while using this class, we have to use type casting and it can produce ClassCastException at runtime. Now we will use generics to rewrite the same class with generics type as shown below.

package com.naresh.generics;

public class GenericsType<T> {

     private T t;

     public T get(){
          return this.t;
     }

     public void set(T t1){
          this.t=t1;
     }

     public static void main(String mnb[]){
          GenericsType<String> type = new GenericsType<>();
          type.set("Pawan Kalyan"); //valid

          GenericsType type1 = new GenericsType(); //raw type
          type1.set("Pawan Kalyan"); //valid
          type1.set(10); //valid and autoboxing support
     }

}

Tip: We can use @SuppressWarnings("rawtypes") annotation to suppress the compiler warning, check out java annotations tutorial.

Also notice that it supports java autoboxing.
Comparable interface is a great example of Generics in interfaces and it’s written as:
import java.util.*;

public interface Comparable<T> {
    public int compareTo(T o);
}

Generics notations and naming Convention

One of the reason Generics looks tough is due to non familiarity of various Generics terms and naming conventions. Once you know meaning and name of various terms in generics you will feel more comfortable with Generics in Java. Following are some of the frequently used terms in Generics

Generic Term
Meaning
Set<E>
Generic Type , E is called formal parameter
Set<Integer>
Parametrized type , Integer is actual parameter here
<T extends Comparable>
Bounded type parameter
<T super Comparable>
Bounded type parameter
Set<?>
Unbounded wildcard
<? extends T>
Bounded wildcard type
<? Super T>
Bounded wildcards
Set
Raw type
<T extends Comparable<T>>
Recursive type bound


T – used to denote type
E – used to denote element
K – keys
V - values
N – for numbers

Generics in Methods and Constructors

Sometimes we don’t want whole class to be parameterized, in that case we can use generics type in methods also. Since constructor is a special kind of method, we can use generics type in constructors too.
Here is a class showing example of generics type in method.
package com.naresg.generics;

public class GenericsMethods {

     //Generics in method
     public static <T> boolean isEqual(GenericsType<T> g1, GenericsType<T> g2){
          return g1.get().equals(g2.get());
     }

     public static void main(String mnb[]){
          GenericsType<String> g1 = new GenericsType<>();
          g1.set("Pawan Kalyan");

          GenericsType<String> g2 = new GenericsType<>();
          g2.set("Pawan Kalyan");

          boolean isEqual = GenericsMethods.<String>isEqual(g1, g2);
          //above statement can be written simply as
          isEqual = GenericsMethods.isEqual(g1, g2);
          //This feature, known as type inference, allows you to invoke a generic method as an ordinary method, without specifying a type between angle brackets.
          //Compiler will infer the type that is needed
     }
}

Generics Bounded Type Parameters

Suppose we want to restrict the type of objects that can be used in the parameterized type, for example in a method that compares two objects and we want to make sure that the accepted objects are Comparables. To declare a bounded type parameter, list the type parameter’s name, followed by the extends keyword, followed by its upper bound, similar like below method.
public static <T extends Comparable<T>> int compare(T t1, T t2){
          return t1.compareTo(t2);
     }
Bounded type parameters can be used with methods as well as classes and interfaces.
Generics supports multiple bounds also, i.e <T extends A & B & C>. In this case A can be an interface or class. If A is class then B and C should be interfaces. We can’t have more than one class in multiple bounds.

Generics and Inheritance

We know that Java inheritance allows us to assign a variable A to another variable B if A is subclass of B. So we might think that any generic type of A can be assigned to generic type of B, but it’s not the case. Lets see this with a simple program.
package com.naresh.generics;

public class GenericsInheritance {

     public static void main(String[] mnb) {
          String str = "Sachin";
          Object obj = new Object();
          obj=str; // works because String is-a Object, inheritance in java

          MyClass<String> myClass1 = new MyClass<String>();
          MyClass<Object> myClass2 = new MyClass<Object>();
          //myClass2=myClass1; // compilation error since MyClass<String> is not a MyClass<Object>
          obj = myClass1; // MyClass<T> parent is Object
     }

     public static class MyClass<T>{}

}
We are not allowed to assign MyClass<String> variable to MyClass<Object> variable because they are not related, in fact MyClass<T> parent is Object.

Generic Classes and Subtyping

We can subtype a generic class or interface by extending or implementing it. The relationship between the type parameters of one class or interface and the type parameters of another are determined by the extends and implements clauses.
For example, ArrayList<E> implements List<E> that extends Collection<E>, so ArrayList<String> is a subtype of List<String> and List<String> is subtype of Collection<String>.
The subtyping relationship is preserved as long as we don’t change the type argument, below shows an example of multiple type parameters.
interface MyList<E,T> extends List<E>{}
The subtypes of List<String> can be MyList<String,Object>, MyList<String,Integer> and so on.

Generics Wildcards

Question mark (?) is the wildcard in generics and represent an unknown type. The wildcard can be used as the type of a parameter, field, or local variable and sometimes as a return type. We can’t use wildcards while invoking a generic method or instantiating a generic class. In following sections, we will learn about upper bounded wildcards, lower bounded wildcards, and wildcard capture.

Generics Upper Bounded Wildcard

Upper bounded wildcards are used to relax the restriction on the type of variable in a method. Suppose we want to write a method that will return the sum of numbers in the list, so our implementation will be something like this.
public static double sum(List<Number> list){
     double sum = 0;
     for(Number n : list){
          sum += n.doubleValue();
     }
     return sum;
}
Now the problem with above implementation is that it won’t work with List of Integers or Doubles because we know that List<Integer> and List<Double> are not related, this is when upper bounded wildcard is helpful. We use generics wildcard with extends keyword and the upper bound class or interface that will allow us to pass argument of upper bound or it’s subclasses types.
package com.naresh.generics;

import java.util.ArrayList;
import java.util.List;

public class GenericsWildcards {

     public static void main(String[] mnb) {
          List<Integer> ints = new ArrayList<>();
          ints.add(3); ints.add(5); ints.add(10);
          double sum = sum(ints);
          System.out.println("Sum of ints="+sum);
     }

     public static double sum(List<? extends Number> list){
          double sum = 0;
          for(Number n : list){
              sum += n.doubleValue();
          }
          return sum;
     }
}

Generics Unbounded Wildcard

Sometimes we have a situation where we want our generic method to be working with all types, in this case unbounded wildcard can be used. Its same as using <? extends Object>.
public static void printData(List<?> list){
     for(Object obj : list){
          System.out.print(obj + "::");
     }
}
We can provide List<String> or List<Integer> or any other type of Object list argument to the printData method. Similar to upper bound list, we are not allowed to add anything to the list.

Generics Lower bounded Wildcard

Suppose we want to add Integers to a list of integers in a method, we can keep the argument type as List<Integer> but it will be tied up with Integers whereas List<Number> and List<Object> can also hold integers, so we can use lower bound wildcard to achieve this. We use generics wildcard (?) with super keyword and lower bound class to achieve this.
We can pass lower bound or any super type of lower bound as an argument in this case, java compiler allows to add lower bound object types to the list.
public static void addIntegers(List<? super Integer> list){
     list.add(new Integer(50));
}

Subtyping using Generics Wildcard

List<? extends Integer>intList=new ArrayList<>()
List<? extends Number>  numList = intList;  // OK. List<? extends Integer> is a subtype of List<? extends Number>

Type Erasure

Generics was added to provide type-checking at compile time and it has no use at run time, so java compiler uses type erasure feature to remove all the generics type checking code in byte code and insert type-casting if necessary. Type erasure ensures that no new classes are created for parameterized types; consequently, generics incur no runtime overhead.
For example if we have a generic class like below;
public class Test<T extends Comparable<T>> {

    private T data;
    private Test<T> next;

    public Test(T a, Test<T> n) {
        this.data = a;
        this.next = n;
    }

    public T getData() { return this.data; }
}
The Java compiler replaces the bounded type parameter T with the first bound interface, Comparable, as below code:
public class Test {

    private Comparable data;
    private Test next;

    public Node(Comparable d:Test t) {
        this.data = d;
        this.next = n;
    }

    public Comparable getData() { return data; }
}
Thats all for generics in java, generics is a really vast topic and requires a lot of time to understand and use it effectively. This post here is an attempt to provide basic details of generics and how can we use it to extend our program with type-safety.