16, ఫిబ్రవరి 2015, సోమవారం

JAVA GENERIC CLASS 1.40 MIN LECTURE


Generic Class
What Are Generics
The term generics means parameterized types. Using generics, it is possible to create a single class that works with different types of data. A class, interface, or method that operates on a parameterized type is called generic.
A Simple Generics Example

// T is a type parameter that will be replaced by a real type
// when an object of type Gen is created.
class Gen<T> {
  T ob; // declare an object of type T
  Gen(T o) {
    ob = o;
  }
  // Return ob.
  T getob() {
    return ob;
  }
  // Show type of T.
  void showType() {
    System.out.println("Type of T is " + ob.getClass().getName());
  }
}

public class Main {
  public static void main(String args[]) {
    Gen<Integer> iOb = new Gen<Integer>(88);
    iOb.showType();
    int v = iOb.getob();
    System.out.println("value: " + v);
    Gen<String> strOb = new Gen<String>("Generics Test");
    strOb.showType();
    String str = strOb.getob();
    System.out.println("value: " + str);
  }
}
 
T is the name of a type parameter. T is used to declare an object. Generics work only with objects Generic types differ based on their type arguments
A Generic Class with Two Type Parameters
You can declare more than one type parameter in a generic type.

// A simple generic class with two type parameters: T and V.
class TwoGen<T, V> {
  T ob1;
  V ob2;
  TwoGen(T o1, V o2) {
    ob1 = o1;
    ob2 = o2;
  }
  void showTypes() {
    System.out.println("Type of T is " + ob1.getClass().getName());
    System.out.println("Type of V is " + ob2.getClass().getName());
  }

  T getob1() {
    return ob1;
  }

  V getob2() {
    return ob2;
  }
}

public class Main {
  public static void main(String args[]) {
    TwoGen<Integer, String> tgObj = new TwoGen<Integer, String>(88, "Generics");
    tgObj.showTypes();
    int v = tgObj.getob1();
    System.out.println("value: " + v);
    String str = tgObj.getob2();
    System.out.println("value: " + str);
  }
}
 
Here is the syntax for declaring a generic class:

class className<type-param-list> {}
 
Here is the syntax for declaring a reference to a generic class:

className<type-arg-list> varName = new className<type-arg-list>(cons-arg-list);
 
The following code declares and uses a Queue<E> generic type.

class Queue<E> {
  private E[] elements;
  private int head=0, tail=0;

  Queue(int size) {
    elements = (E[]) new Object[size];
  }

  void insert(E element) throws QueueFullException {
    if (isFull())
      throw new QueueFullException();
    elements[tail] = element;
    tail = (tail + 1) % elements.length;
  }

  E remove() throws QueueEmptyException {
    if (isEmpty()){
      throw new QueueEmptyException();
    }
    E element = elements[head];
    head = (head + 1) % elements.length;
    return element;
  }

  boolean isEmpty() {
    return head == tail;
  }

  boolean isFull() {
    return (tail + 1) % elements.length == head;
  }
}
class QueueEmptyException extends Exception {
}

class QueueFullException extends Exception {
}
public class Main{
  public static void main(String[] args) throws QueueFullException, QueueEmptyException {
    Queue<String> queue = new Queue<String>(6);
    System.out.println("Empty: " + queue.isEmpty());
    System.out.println("Full: " + queue.isFull());
    queue.insert("A");
    queue.insert("B");
    queue.insert("C");
    queue.insert("D");
    queue.insert("E");
    System.out.println("Empty: " + queue.isEmpty());
    System.out.println("Full: " + queue.isFull());
    System.out.println("Removing " + queue.remove());
    System.out.println("Empty: " + queue.isEmpty());
    System.out.println("Full: " + queue.isFull());
    System.out.println("Adding F");
    queue.insert("F");
    while (!queue.isEmpty()){
      System.out.println("Removing " + queue.remove());
    }
     
    System.out.println("Empty: " + queue.isEmpty());
    System.out.println("Full: " + queue.isFull());
  }
}
 
Output:

Empty: true
Full: false
Empty: false
Full: true
Removing A
Empty: false
Full: false
Adding F
Removing B
Removing C
Removing D
Removing E
Removing F
Empty: true
Full: false

Generic Bounded Types

When specifying a type parameter, you can create an upper bound from which all type arguments must be derived. This is accomplished through the use of an extends clause when specifying the type parameter:
 
<T extends superClassName>
  
This specifies that T can only be replaced by superClassName, or subclasses of superClassName. Thus, superclass defines an inclusive, upper limit.
 
class Calculator<T extends Number> {
  T[] nums;
  Calculator(T[] o) {
    nums = o;
  }
  double average() {
    double sum = 0.0;
    for (int i = 0; i < nums.length; i++){
      sum += nums[i].doubleValue();
    }
    return sum / nums.length;
  }
}
public class Main {
  public static void main(String args[]) {
    Integer inums[] = { 1, 2, 3, 4, 5 };
    Calculator<Integer> iob = new Calculator<Integer>(inums);
    double v = iob.average();
    System.out.println("iob average is " + v);
    Double dnums[] = { 1.1, 2.2, 3.3, 4.4, 5.5 };
    Calculator<Double> dob = new Calculator<Double>(dnums);
    double w = dob.average();
    System.out.println("dob average is " + w);
  }
}
  
In addition to using a class type as a bound, you can also use an interface type. You can specify multiple interfaces as bounds.
A bound can include both a class type and one or more interfaces. In this case, the class type must be specified first.
When a bound includes an interface type, only type arguments that implement that interface are legal.
When specifying a bound that has a class and an interface, or multiple interfaces, use the & operator to connect them.
For example,
 
class Gen<T extends MyClass & MyInterface> {}
  
Any type argument passed to T must be a subclass of MyClass and implement MyInterface.

Generic Wildcard Arguments

To create a generic method, you use the wildcard argument. The wildcard argument is specified by the ?, and it represents an unknown type.
 
class Calculator<T extends Number> {
  T[] nums;
  Calculator(T[] o) {
    nums = o;
  }
  double average() {
    double sum = 0.0;
    for (int i = 0; i < nums.length; i++){
      sum += nums[i].doubleValue();
    }
    return sum / nums.length;
  }
}
public class Main {
  boolean sameAvg(Calculator<?> ob) {
    if (1.2 == ob.average())
      return true;
    return false;
  }
 
  public static void main(String args[]) {
  }
}
  
Calculator<?> matches any Stats object, allowing any two Stats objects to have their averages compared.
The following program demonstrates this:
 
class Calculator<T extends Number> {
  T[] nums;
  Calculator(T[] o) {
    nums = o;
  }
  double average() {
    double sum = 0.0;
    for (int i = 0; i < nums.length; i++)
      sum += nums[i].doubleValue();
    return sum / nums.length;
  }
  boolean sameAvg(Calculator<?> ob) {
    if (average() == ob.average())
      return true;
    return false;
  }
}
public class Main {
  public static void main(String args[]) {
    Integer inums[] = { 1, 2, 3, 4, 5 };
    Calculator<Integer> iob = new Calculator<Integer>(inums);
 
    Double dnums[] = { 1.1, 2.2, 3.3, 4.4, 5.5 };
    Calculator<Double> dob = new Calculator<Double>(dnums);
 
    if (iob.sameAvg(dob))
      System.out.println("are the same.");
    else
      System.out.println("differ.");
  }
}
  

Generic Bounded Wildcards

Wildcard arguments can be bounded in the same way that a type parameter can be bounded. A bounded wildcard is important when creating a generic type that will operate on a class hierarchy.
A bounded wildcard specifies either an upper bound or a lower bound for the type argument.
 
class TwoD {
  int x, y;
  TwoD(int a, int b) {
    x = a;
    y = b;
  }
}
 
// Three-dimensional coordinates.
class ThreeD extends TwoD {
  int z;
 
  ThreeD(int a, int b, int c) {
    super(a, b);
    z = c;
  }
}
class Map<T extends TwoD> {
  T[] coords;
 
  Map(T[] o) {
    coords = o;
  }
}
 
public class Main {
  static void showXY(Map<?> c) {
    for (int i = 0; i < c.coords.length; i++){
      System.out.println(c.coords[i].x + " " + c.coords[i].y);
    }      
  }
  static void showXYZ(Map<? extends ThreeD> c) {
    for (int i = 0; i < c.coords.length; i++){
      System.out.println(c.coords[i].x + " " + c.coords[i].y + " "
          + c.coords[i].z);
    }
  }
  public static void main(String args[]) {
    TwoD td[] = { new TwoD(0, 0), new TwoD(-1, -2) };
    Map<TwoD> map = new Map<TwoD>(td);
    System.out.println("Contents of tdlocs.");
 
    showXY(map);
  }
}
  
In general, to establish an upper bound for a wildcard, use the following type of wildcard expression:
 
<? extends superclass>
  
superclass is the name of the class that serves as the upper bound. This is an inclusive clause.
You can specify a lower bound for a wildcard by adding a super clause to a wildcard declaration.
 
<? super subclass>
  
In this case, only classes that are superclasses of subclass are acceptable arguments. This is an exclusive clause, because it will not match the class specified by subclass.

Generic Method

It is possible to create a generic method that is enclosed within a non-generic class.
 
public class Main {
  static <T, V extends T> boolean isIn(T x, V[] y) {
    for (int i = 0; i < y.length; i++) {
      if (x.equals(y[i])) {
        return true;
      }
    }
    return false;
  }
 
  public static void main(String args[]) {
    Integer nums[] = { 1, 2, 3, 4, 5 };
    if (isIn(2, nums)){
      System.out.println("2 is in nums");
    }
    String strs[] = { "one", "two", "three", "four", "five" };
    if (isIn("two", strs)){
      System.out.println("two is in strs");
    }
  }
}
  
The following code declares a copyList() generic method.
 
import java.util.ArrayList;
import java.util.List;
 
public class Main {
  public static void main(String[] args) {
    List<String> ls = new ArrayList<String>();
    ls.add("A");
    ls.add("B");
    ls.add("C");
    List<String> lsCopy = new ArrayList<String>();
    copyList(ls, lsCopy);
    List<Integer> lc = new ArrayList<Integer>();
    lc.add(0);
    lc.add(5);
    List<Integer> lcCopy = new ArrayList<Integer>();
    copyList(lc, lcCopy);
  }
 
  static <T> void copyList(List<T> src, List<T> dest) {
    for (int i = 0; i < src.size(); i++)
      dest.add(src.get(i));
  }
 
}
  

Generic Constructors

It is possible for constructors to be generic, even if their class is not. For example, consider the following short program:
 
class MyClass {
  private double val;
 
  <T extends Number> MyClass(T arg) {
    val = arg.doubleValue();
  }
 
  void showval() {
    System.out.println("val: " + val);
  }
}
 
public class Main {
  public static void main(String args[]) {
    MyClass test = new MyClass(100);
    MyClass test2 = new MyClass(123.5F);
    test.showval();
    test2.showval();
  }
}
  

Generic Interfaces

Generic interfaces are specified like generic classes.
 
interface MinMax<T extends Comparable<T>> {
  T max();
}
class MyClass<T extends Comparable<T>> implements MinMax<T> {
  T[] vals;
  MyClass(T[] o) {
    vals = o;
  }
  public T max() {
    T v = vals[0];
    for (int i = 1; i < vals.length; i++) {
      if (vals[i].compareTo(v) > 0) {
        v = vals[i];
      }
    }
    return v;
  }
}
 
public class Main {
  public static void main(String args[]) {
    Integer inums[] = { 3, 6, 2, 8, 6 };
    Character chs[] = { 'b', 'r', 'p', 'w' };
    MyClass<Integer> a = new MyClass<Integer>(inums);
    MyClass<Character> b = new MyClass<Character>(chs);
    System.out.println(a.max());
    System.out.println(b.max());
  }
}
  
In general, if a class implements a generic interface, then that class must also be generic.
If a class implements a specific type of generic interface, such as shown here:
 
class MyClass implements MinMax<Integer> { // OK
  
then the implementing class does not need to be generic.
Here is the generalized syntax for a generic interface:
 
interface interface-name<type-param-list> { // ...
  
type-param-list is a comma-separated list of type parameters. When a generic interface is implemented, you must specify the type arguments, as shown here:
 
class class-name<type-param-list> 
   implements interface-name<type-arg-list> {
  

Raw Types and Legacy Code

To handle the transition to generics, Java allows a generic class to be used without any type arguments.
Here is an example that shows a raw type in action:
 
class MyClass<T> {
  T ob;
  MyClass(T o) {
    ob = o;
  }
  T getob() {
    return ob;
  }
}
public class Main {
  public static void main(String args[]) {
    MyClass raw = new MyClass(new Double(98.6));
    double d = (Double) raw.getob();
    System.out.println("value: " + d);
  }
}
  

Generic Class Hierarchies

A generic class can act as a superclass or be a subclass. In a generic hierarchy, any type arguments needed by a generic superclass must be passed up the hierarchy by all subclasses.
Using a Generic Superclass
 
class MyClass<T> {
  T ob;
  MyClass(T o) {
    ob = o;
  }
  T getob() {
    return ob;
  }
}
class MySubclass<T, V> extends MyClass<T> {
  V ob2;
 
  MySubclass(T o, V o2) {
    super(o);
    ob2 = o2;
  }
 
  V getob2() {
    return ob2;
  }
}
public class Main {
  public static void main(String args[]) {
    MySubclass<String, Integer> x = new MySubclass<String, Integer>("Value is: ", 99);
    System.out.print(x.getob());
    System.out.println(x.getob2());
  }
}
  
A Generic Subclass
It is perfectly acceptable for a non-generic class to be the superclass of a generic subclass.
 
class MyClass {
  int num;
 
  MyClass(int i) {
    num = i;
  }
 
  int getnum() {
    return num;
  }
}
class MySubclass<T> extends MyClass {
  T ob;
  MySubclass(T o, int i) {
    super(i);
    ob = o;
  }
  T getob() {
    return ob;
  }
}
public class Main {
  public static void main(String args[]) {
     MySubclass<String> w = new MySubclass<String>("Hello", 4);
    System.out.print(w.getob() + " ");
    System.out.println(w.getnum());
  }
}
  

Run-Time Type Comparisons Within a Generic Hierarchy

The instanceof operator can be applied to objects of generic classes.
 
class Gen<T> {
  T ob;
 
  Gen(T o) {
    ob = o;
  }
  T getob() {
    return ob;
  }
}
class Gen2<T> extends Gen<T> {
  Gen2(T o) {
    super(o);
  }
}
 
public class Main {
  public static void main(String args[]) {
    Gen<Integer> iOb = new Gen<Integer>(88);
    Gen2<Integer> iOb2 = new Gen2<Integer>(99);
    Gen2<String> strOb2 = new Gen2<String>("Generics Test");
    System.out.println("iOb2 is instance of Gen2"+(iOb2 instanceof Gen2<?>));
    System.out.println("iOb2 is instance of Gen"+(iOb2 instanceof Gen<?>));
    System.out.println("strOb2 is instance of Gen2"+(strOb2 instanceof Gen2<?>));
    System.out.println("strOb2 is instance of Gen"+(strOb2 instanceof Gen<?>));
    System.out.println("iOb is instance of Gen2"+(iOb instanceof Gen2<?>));
    System.out.println("iOb is instance of Gen"+(iOb instanceof Gen<?>));
  }
}
  

Casting

You can cast one instance of a generic class into another only if the two are compatible and their type arguments are the same.
For example, assuming the foregoing program, this cast is legal:
 
class Gen<T> {
  T ob;
 
  Gen(T o) {
    ob = o;
  }
  T getob() {
    return ob;
  }
}
class Gen2<T> extends Gen<T> {
  Gen2(T o) {
    super(o);
  }
}
 
public class Main {
  public static void main(String args[]) {
    Gen<Integer> iOb = new Gen<Integer>(88);
    Gen2<Integer> iOb2 = new Gen2<Integer>(99);
    Gen2<String> strOb2 = new Gen2<String>("Generics Test");
    iOb = (Gen<Integer>) iOb2;
  }
}
  
because iOb2 is an instance of Gen<Integer>. But, this cast:
 
class Gen<T> {
  T ob;
 
  Gen(T o) {
    ob = o;
  }
  T getob() {
    return ob;
  }
}
class Gen2<T> extends Gen<T> {
  Gen2(T o) {
    super(o);
  }
}
 
public class Main {
  public static void main(String args[]) {
    Gen<Integer> iOb = new Gen<Integer>(88);
    Gen2<Integer> iOb2 = new Gen2<Integer>(99);
    Gen2<String> strOb2 = new Gen2<String>("Generics Test");
    //iOb = (Gen<Long>) iOb2;//wrong
  }
}
  
is not legal because iOb2 is not an instance of Gen<Long>.

Overriding Methods in a Generic Class

A method in a generic class can be overridden like any other method.
 
class Gen<T> {
  T obj;
  Gen(T o) {
    obj = o;
  }
  T getob() {
    System.out.print("Gen's getob(): ");
    return obj;
  }
}
class Gen2<T> extends Gen<T> {
  Gen2(T o) {
    super(o);
  }
  T getob() {
    System.out.print("Gen2's getob(): ");
    return obj;
  }
}
public class Main {
  public static void main(String args[]) {
    Gen<Integer> iOb = new Gen<Integer>(88);
    Gen2<String> strOb2 = new Gen2<String>("Generics Test");
    System.out.println(iOb.getob());
    System.out.println(strOb2.getob());
  }
}
  

Generic Restrictions

Type Parameters Can't Be Instantiated

It is not possible to create an instance of a type parameter. For example, consider this class:
 
// Can't create an instance of T. 
class Gen<T> {
  T ob;
 
  Gen() {
    ob = new T(); // Illegal!!!
  }
}
  

Restrictions on Static Members

No static member can use a type parameter declared by the enclosing class. For example, all of the static members of this class are illegal:
 
class Wrong<T> {
  // Wrong, no static variables of type T.
  static T ob;
 
  // Wrong, no static method can use T.
  static T getob() {
    return ob;
  }
 
  // Wrong, no static method can access object of type T.
  static void showob() {
    System.out.println(ob);
  }
}
  You can declare static generic methods with their own type parameters.

Generic Array Restrictions

You cannot instantiate an array whose base type is a type parameter. You cannot create an array of type specific generic references.
The following short program shows both situations:
 
class MyClass<T extends Number> {
  T ob;
  T vals[];
 
  MyClass(T o, T[] nums) {
    ob = o;
    vals = nums;
  }
}
public class Main {
  public static void main(String args[]) {
    Integer n[] = { 1 };
    MyClass<Integer> iOb = new MyClass<Integer>(50, n);
    // Can't create an array of type-specific generic references.
    // Gen<Integer> gens[] = new Gen<Integer>[10]; 
    MyClass<?> gens[] = new MyClass<?>[10]; // OK
  }
}
  


కామెంట్‌లు లేవు:

కామెంట్‌ను పోస్ట్ చేయండి