Object Oriented Programming - Lecture 12 - Generics

Object-Oriented Programming - Lecture 12 by Faiza Dahri

Introduction

  • Generics enable the creation of classes, interfaces, and methods where the data type is specified as a parameter.

  • Introduced in Java with JDK 1.5.

  • Generics are parameterized types.

  • They enhance type-safety.

  • Generics improve code stability by detecting more bugs at compile time.

Benefits of Generics

  • Generics provide stronger type checks at compile time.

  • They eliminate the need for explicit casts.

    • Example without generics:
      java List list = new ArrayList(); list.add("hello"); String s = (String) list.get(0);

    • Example using generics:
      java List<String> list = new ArrayList<String>(); list.add("hello"); String s = list.get(0); // No cast required

  • Generics enable the implementation of generic algorithms that:

    • Work on collections of different types.

    • Can be customized.

    • Are type-safe and easier to read.

Advantage of Generics

  • A key advantage is the ability to create type-safe code, catching type-mismatch errors at compile time.

Generic Classes and Interfaces

  • Example of a generic class:

    class Gen<T> {
        T ob;
        Gen(T o) { ob = o; }
        T getob() { return ob; }
        void showType() {
            System.out.println("Type of T is " + ob.getClass().getName());
        }
    }
    
    class GenDemo {
        public static void main(String args[]) {
            Gen<Integer> iOb;
            iOb = new Gen<Integer>(88);
            iOb.showType();
            int v = iOb.getob();
            System.out.println("value: " + v);    Gen&lt;String&gt; strOb = new Gen&lt;String&gt;("Generics Test");
        strOb.showType();
        String str = strOb.getob();
        System.out.println("value: " + str);
    }
    }
    
  • Generics work only with Objects.

    • Type argument must be a class type.

    • Gen<int> strOb = new Gen<int>(53); is an error because int is a primitive type, not a class.

  • A reference of one specific version of a generic type is not type-compatible with another version of the same generic type.

    • iOb = strOb; is wrong.

General Form of Generic Class

  • Syntax for declaring a generic class:
    class class-name<type-param-list> { // ... }

  • Syntax for declaring a reference to a generic class:
    class-name<type-arg-list> var-name = new class-name<type-arg-list>(cons-arg-list);

Generic Class with Multiple Type Parameters

  • Example:

    class TwoGen<T, V> {
        T obl;
        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; }
    }
    
    class SimpGen {
        public static void main(String args[]) {
            TwoGen<Integer, String> t = new TwoGen<Integer, String>(16920, "Ravi Kant");
            t.showTypes();
            int v = t.getob1();
            System.out.println("value: " + v);
            String str = t.getob2();
            System.out.println("value: " + str);
        }
    }
    

Problem Example

  • Create a generic class that contains a method that returns the average of an array of numbers of any type (integers, floats, doubles).

  • Possible Solution:

    class Stats<T> {
        T[] nums;Stats(T[] o) {
        nums = o;
    }
    
    double average() {
        double sum = 0.0;
        for (int i = 0; i &lt; nums.length; i++)
            sum += nums[i].doubleValue(); // Error!!!
        return sum / nums.length;
    }
    }
    
  • Why Error?

    • The compiler doesn't know that you intend to create Stats objects using only numeric types.

    • The doubleValue() method is unknown.

    • We need to tell the compiler that we intend to pass only numeric types to T.

Wildcard Generics

*Problem:
*Create a generic class that contains a method sameAvg() that determines if two Stats objects contain arrays that yield the same average, no matter what type of numeric data each object holds.

  • Example:

    import java.util.*;
    
    public class WildcardExample {
        public static void printList(List<?> list) {
            for (Object elem : list) {
                System.out.println(elem);
            }
        }public static void main(String[] args) {
        List&lt;Integer&gt; intList = Arrays.asList(1, 2, 3);
        List&lt;String&gt; strList = Arrays.asList("A", "B", "C");
        printList(intList); // Integers print
        printList(strList); // Strings print
    }
    }
    

Wildcard Argument

  • Matches the validity of object.

  • Specified by ?, representing an unknown type.

  • Example:
    java boolean same_Avg(Stats<?> ob) { if (average() == ob.average()) return true; return false; }

Generic Methods

  • Can declare a generic method that uses one or more type parameters.

  • Methods inside a generic class are automatically generic relative to the type parameters.

  • Can create a generic method within a non-generic class.

Generic Interfaces

  • Specified just like generic classes.

  • Example:

    interface MinMax<T extends Comparable<T>> {
        T min();
        T max();
    }
    
    class My<T extends Comparable<T>> implements MinMax<T> {
    }
    
  • The implementing class must specify the same bound.

  • Once the bound is established, it need not be specified again in the implements clause.

Generic Constructors

  • Constructors can be generic, even if their class is not.

  • Example:

    class GenCons {
        private double val;&lt;T extends Number&gt; GenCons(T arg) {
        val = arg.doubleValue();
    }
    
    void show_val() { System.out.println("val: " + val); }
    }
    

Erasure

  • Generic code must be compatible with pre-existing, non-generic code.

  • Changes to Java syntax or the JVM had to avoid breaking older code.

  • Java implements Generics using Erasure to avoid breaking older codes.

Working of Erasure

  • During compilation, all generic type information is removed (erased).

  • Type parameters are replaced with their bound type (Object if no explicit bound is specified).

  • Appropriate casts are applied to maintain type compatibility with the types specified by the type arguments.

Erasures

  • The compiler enforces type compatibility.

  • No type parameters exist at run time.

  • They are simply a source-code mechanism.

Generic Restrictions

  1. Type Parameters Can't Be Instantiated:

    • Cannot create an instance of a type parameter.

    • Example:

      class Gen<T> {
          T ob;Gen() {
          ob = new T(); // Illegal
      }
      }
      
    • Because T does not exist at run time, the compiler cannot know what type of object to create.

  2. Restrictions on Static Members:

    • No static member can use a type parameter declared by the enclosing class.

    • Example:
      java class Wrong<T> { static T ob; static T getob() { return ob; } static void showob() { System.out.println(ob); } }

    • Can declare static generic methods, which define their own type parameters.

  3. Generic Array Restrictions:

    • Cannot instantiate an array whose base type is a type parameter.

    • Cannot create an array of type-specific generic references.

    • Example:

      class Gen<T extends Number> {
          T ob;
          T vals[]; // OKGen(T o, T[] nums) {
          ob = o;
          // vals = new T[10]; // This statement is illegal.
          vals = nums; // OK to assign reference to existent array
      }
      }
      
      class GenArrays {
          public static void main(String args[]) {
              Integer n[] = {1, 2, 3, 4, 5};
              Gen<Integer> iOb = new Gen<Integer>(50, n);    // Can't create an array of type-specific generic references.
          // Gen&lt;Integer&gt; gens[] = new Gen&lt;Integer&gt;[10]; // Wrong!
          Gen&lt;?&gt; gens[] = new Gen&lt;?&gt;[10]; // OK
      }
      }
      
  4. Generic Exception Restrictions:

    • A generic class cannot extend Throwable.

    • Cannot create generic exception classes.