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<String> strOb = new Gen<String>("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 becauseintis 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 < nums.length; i++) sum += nums[i].doubleValue(); // Error!!! return sum / nums.length; } }Why Error?
The compiler doesn't know that you intend to create
Statsobjects 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<Integer> intList = Arrays.asList(1, 2, 3); List<String> 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
implementsclause.
Generic Constructors
Constructors can be generic, even if their class is not.
Example:
class GenCons { private double val;<T extends Number> 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
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
Tdoes not exist at run time, the compiler cannot know what type of object to create.
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.
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<Integer> gens[] = new Gen<Integer>[10]; // Wrong! Gen<?> gens[] = new Gen<?>[10]; // OK } }
Generic Exception Restrictions:
A generic class cannot extend
Throwable.Cannot create generic exception classes.