Generic Programming
Generic Programming
Motivation
Motivation
• It would be nice if we could write a single sort
method that could sort the elements in an
Integer array, a String array or an array of
any type that supports ordering.
• It would also be nice if we could write a single
Stack class that could be used as a Stack of
integers, a Stack of floating-point numbers, a Stack
integers, a Stack of floating-point numbers, a Stack
of String’s or a Stack of any other type.
• Detecting type mismatches at compile time
known as compile-time type safety. For example, if
a Stack stores only integers, attempting to push a
String on to that Stack should issue a compile-time
error.
What is Generic Programming?
What is Generic Programming?
• A style of computer programming in which
algorithms are written in terms of to-be-specified-
later types.
• The aim is to write algorithms that are capable of
operating on a wide range of data structures, by
finding commonalities among similar
implementations of the same algorithm.
implementations of the same algorithm.
Why Generic Programming?
Why Generic Programming?
• We don’t have to put much thought into
anticipating the types of elements that we are
dealing with.
• We are not writing our methods and classes for a
specific data type, but rather for a general data type.
• No extra work is needed when new data types are
introduced to the software; we do not have to write
introduced to the software; we do not have to write
new versions of classes and methods to operate one
newly added data types, thus contributing to code
reuse.
• Expressing algorithms with minimal assumptions
about data abstractions, and vice versa, thus making
them as interoperable as possible.
Generic Programming in Java
Note: Generics were added to the Java language
Note: Generics were added to the Java language
syntax in version 1.5. This means that code using
Generics will not compile with Java 1.4 and less
Generic Methods
Generic Methods
Without using generics, printing an array of objects would be done by
method overloading:
public static void printArray( Integer[] Arr)
{
for (int count=0; count<Arr.length; count++)
System.out.printf( "%s ", element );
System.out.println();
}
public static void printArray( Double[] Arr)
{
for (int count=0; count<Arr.length; count++)
for (int count=0; count<Arr.length; count++)
System.out.printf( "%s ", element );
System.out.println();
}
public static void printArray( String[] Arr)
{
for (int count=0; count<Arr.length; count++)
System.out.printf( "%s ", element );
System.out.println();
}
And so on.
• Declaring a generic method that takes an array of objects
of an arbitrary class and prints its String
representation:
public static < E > void printArray( E[] Arr)
{
for (int count=0; count<Arr.length; count++)
System.out.printf( "%s ", Arr[count]);
System.out.println();
System.out.println();
}
• E is called a type parameter.
• Programming error:
When declaring a generic method, failing to place a type parameter
section before the return type of a method is a syntax error the
compiler will not understand the type parameter name when it is
encountered in the method.
• In both cases, the main method will look the same:
public static void main(String args[])
{
Integer[] IntegerArr = {1,2,3,4,5,6};
Double[] DoubleArr = {1.1, 1.2, 1.3};
String[] StringArray = {“Nice”, “to“, “meet“, “you.“};
System.out.println(“Integer array:”);
printArray(IntegerArr);
System.out.println(“Double array:”);
printArray(DoubleArr);
System.out.println(“String array:”);
printArray(StringArr);
}
Also, the output
is identical in both cases:
Integer array:
1 2 3 4 5 6
Double array:
1.1 1.2 1.3
String array:
Nice to meet you.
• When the compiler translates the generic method printArray into
Java bytecodes, it removes the type parameter section and replaces the
type parameters with actual types. This process is known as erasure.
• By default all generic types are replaced with type Object.
• So the compiled version of method printArray is:
public static void printArray( Object[] Arr)
{
for (int count=0; count<Arr.length; count++)
System.out.printf( "%s ", Arr[count]);
System.out.println();
}
• There is only one copy of this code that is used for all printArray calls
in the example. This is quite different from other, similar mechanisms,
such as C++'s templates in which a separate copy of the source code is
generated and compiled for every type passed as an argument to the
method.
• We’ve eliminated the need for the overloaded
methods of, saving 20 lines of code.
• We’ve created a reusable method.
• The printArray example could have been written
by using an array of Objects as a parameter. This
by using an array of Objects as a parameter. This
would have yielded the same results because any
Object can be output as a String.
• The benefits become apparent when the method
also uses a type parameter as the method's return
type, as we will soon see.
• Example: iterative binary search
public static <T extends Comparable> int binarySearch(T[] Arr, T key )
{
int low = 0;
int high = Arr.length - 1;
int mid;
while( low <= high )
{
mid = ( low + high ) / 2;
if(Arr[ mid ].compareTo(key)< 0)
low = mid + 1;
low = mid + 1;
else if(Arr[ mid ].compareTo(key)> 0)
high = mid - 1;
else
return mid;
}
return -1;
}
• Declaring a generic method with a return type that finds
the maximum of an array of an arbitrary class that
implements the interface Comparable:
public static <T extends Comparable> T Max(T[] Arr)
{
T max=Arr[0];
for(int c=0;c<Arr.length;c++)
if(max.compareTo(Arr[c])<1)
if(max.compareTo(Arr[c])<1)
max=Arr[c];
return max;
}
• T extends Comparable means that only objects of
classes that implement interface Comparable can be used
with this method.
• The interface Comparable imposes a total ordering on
the objects of each class that implements it.
• Note that type parameter declarations that bound the
parameter always use keyword extends regardless of
whether the type parameter extends a class or implements
an interface.
• A benefit of implementing the interface Comparable is
that Comparable objects can be used with the sorting
(e.g., Selection sort) and searching (e.g., binary search)
algorithms that are based on comparing objects.
public static void main(String args[])
{
String s[]={"Cc", "Dw", "Ma", "Ad"};
Integer a[]={1, 2, 3, 44, 0};
Double d[]={1.1, 1.2, 66.3, 44.1, 23.44};
System.out.println("Max of String array is “ + Max(s));
System.out.println("Max of Integer array is "+ Max(a));
System.out.println("Max of Double array is “ + Max(d));
}
• The output is:
• The output is:
Max of String array is Ma
Max of Integer array is 44
Max of Double array is 66.3
• We couldn’t have written the method Max by
using class Object, simply because, class Object
does not implement the interface Comparable,
thus, it does not have a compareTo method, in the
sense that comparing is not meaningful for all kinds
of objects.
Overloading generic methods
• A generic method may be overloaded; a class can
provide two or more generic methods that specify the
same method name but different method parameters.
• A generic method can also be overloaded by non-
generic methods that have the same method name and
number of parameters.
• When the compiler encounters a method call, it
• When the compiler encounters a method call, it
performs a matching process to determine which method
to invoke.
• A precise match is the aim; in which the method names
and argument types of the method call match those of a
specific method declaration. If there is no such method,
the compiler determines whether there is an inexact but
applicable matching method.
Generic Classes
Classes Can Take Parameters
Classes Can Take Parameters
• The concept of a data structure (e.g., a stack) can
be understood independently of the type of
elements it manipulates.
• Generic classes provide a means for describing the
concept of a class in a type-independent manner.
• We can then instantiate type-specific objects of
the generic class.
the generic class.
• For example, a generic Stack class could be the
basis for creating many Stack classes (e.g., "Stack of
Double," "Stack of Integer," "Stack of Character,"
"Stack of Employee," etc.).
• Generic classes provide a wonderful opportunity
for software reusability.
• Example: a generic linked list class
class Node<T>
{
public T Data;
public Node Next;
public Node(T data)
{
Data=data;
Data=data;
}
public void DisplayData()
{
System.out.println(Data+" ");
}
}
class GenericLinkedList<T>
{
public Node<T> First;
public GenericLinkedList()
{
First=null;
}
public void Insert(T key)
{
Node<T> New=new Node<T>(key);
New.Next=First;
First=New;
}
public T Find(T key)
public T Find(T key)
{
Node<T> Current=First;
while(!Current.Data.equals(key))
{
if(Current.Next==null)
return null;
else
Current=Current.Next;
}
return Current.Data;
}
… Next slide
public void DisplayList()
{
Node<T> Current=First;
while(Current!=null)
{
Current.DisplayData();
Current=Current.Next;
}
System.out.println();
}
} //end of class GenericLinkedList<T>
import java.math.BigInteger;
class Test
{
public static void main(String args[])
{
GenericLinkedList <BigInteger> ListBigInteger=new
GenericLinkedList<BigInteger>();
GenericLinkedList <Integer> ListInteger=new
GenericLinkedList<Integer>();
for(int c=1;c<=10;c++)
ListBigInteger.Insert(BigInteger.TEN.pow(10*c));
ListBigInteger.Insert(BigInteger.TEN.pow(10*c));
for(int c=1;c<=15;c++)
ListInteger.Insert(c);
System.out.println("BigInteger list:");
ListBigInteger.DisplayList();
System.out.println("Integer list:");
ListInteger.DisplayList();
… Next slide
BigInteger B=ListBigInteger.Find(BigInteger.TEN.pow(10*3));
if(B==null)
System.out.println(BigInteger.TEN.pow(10*3)+" is not
found in ListBigInteger.");
else
System.out.println(BigInteger.TEN.pow(10*3)+" is found
in ListBigInteger.");
Integer N=ListInteger.Find(5);
if(N==null)
System.out.println(5+" is not found in ListInteger.");
System.out.println(5+" is not found in ListInteger.");
else
System.out.println(5+" is found in ListBigInteger.");
}
} //end of class Test
• The output is:
BigInteger list:
10000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000
10000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000
10000000000000000000000000000000000000000000000000000000000000000
0000000000000000
10000000000000000000000000000000000000000000000000000000000000000
000000
000000
1000000000000000000000000000000000000000000000000000000000000
100000000000000000000000000000000000000000000000000
10000000000000000000000000000000000000000
1000000000000000000000000000000
100000000000000000000
10000000000
Integer list:
15
14
13
12
11
10
9
8
7
6
6
5
4
3
2
1
1000000000000000000000000000000 is found in
ListBigInteger.
5 is found in ListBigInteger.
Wildcards
Wildcards
import java.util.ArrayList;
public class Wildcards
{
public static void main(String args[])
{
ArrayList<Number> Arr=new ArrayList<Number>();
for(int c=0;c<9;c++)
{
Arr.add(new Integer(c));
Arr.add(new Double(1.1*c));
}
}
Print(Arr);
}
public static void Print(ArrayList<Object> A)
{
for(Object N: A)
System.out.println(N);
}
}
• Pop quiz: will the previous program compile?
• No, it won’t compile. Here is the compilation error message:
Method Print in class Pack.Wildcards can not be applied
to given types
required: java.util.ArrayList<java.lang.Object>
found: java.util.ArrayList<java.lang.Integer>
• Translation:
You might expect that method Print would also work for ArrayLists
that contain elements of any type, such as ArrayList< Integer>. The
that contain elements of any type, such as ArrayList< Integer>. The
problem is that ArrayList<Object> is not considered to be a
supertype of all kinds of ArrayLists.
Thanks for listening/viewing
Feel free to send any comments or
suggestions
Presentation by: Muhammad Alhalaby
Email: muhammad.alhalaby@gmail.com

Generic Programming

  • 1.
  • 2.
  • 3.
    • It wouldbe nice if we could write a single sort method that could sort the elements in an Integer array, a String array or an array of any type that supports ordering. • It would also be nice if we could write a single Stack class that could be used as a Stack of integers, a Stack of floating-point numbers, a Stack integers, a Stack of floating-point numbers, a Stack of String’s or a Stack of any other type. • Detecting type mismatches at compile time known as compile-time type safety. For example, if a Stack stores only integers, attempting to push a String on to that Stack should issue a compile-time error.
  • 4.
    What is GenericProgramming? What is Generic Programming?
  • 5.
    • A styleof computer programming in which algorithms are written in terms of to-be-specified- later types. • The aim is to write algorithms that are capable of operating on a wide range of data structures, by finding commonalities among similar implementations of the same algorithm. implementations of the same algorithm.
  • 6.
    Why Generic Programming? WhyGeneric Programming?
  • 7.
    • We don’thave to put much thought into anticipating the types of elements that we are dealing with. • We are not writing our methods and classes for a specific data type, but rather for a general data type. • No extra work is needed when new data types are introduced to the software; we do not have to write introduced to the software; we do not have to write new versions of classes and methods to operate one newly added data types, thus contributing to code reuse. • Expressing algorithms with minimal assumptions about data abstractions, and vice versa, thus making them as interoperable as possible.
  • 8.
    Generic Programming inJava Note: Generics were added to the Java language Note: Generics were added to the Java language syntax in version 1.5. This means that code using Generics will not compile with Java 1.4 and less
  • 9.
  • 10.
    Without using generics,printing an array of objects would be done by method overloading: public static void printArray( Integer[] Arr) { for (int count=0; count<Arr.length; count++) System.out.printf( "%s ", element ); System.out.println(); } public static void printArray( Double[] Arr) { for (int count=0; count<Arr.length; count++) for (int count=0; count<Arr.length; count++) System.out.printf( "%s ", element ); System.out.println(); } public static void printArray( String[] Arr) { for (int count=0; count<Arr.length; count++) System.out.printf( "%s ", element ); System.out.println(); } And so on.
  • 11.
    • Declaring ageneric method that takes an array of objects of an arbitrary class and prints its String representation: public static < E > void printArray( E[] Arr) { for (int count=0; count<Arr.length; count++) System.out.printf( "%s ", Arr[count]); System.out.println(); System.out.println(); } • E is called a type parameter. • Programming error: When declaring a generic method, failing to place a type parameter section before the return type of a method is a syntax error the compiler will not understand the type parameter name when it is encountered in the method.
  • 12.
    • In bothcases, the main method will look the same: public static void main(String args[]) { Integer[] IntegerArr = {1,2,3,4,5,6}; Double[] DoubleArr = {1.1, 1.2, 1.3}; String[] StringArray = {“Nice”, “to“, “meet“, “you.“}; System.out.println(“Integer array:”); printArray(IntegerArr); System.out.println(“Double array:”); printArray(DoubleArr); System.out.println(“String array:”); printArray(StringArr); } Also, the output is identical in both cases: Integer array: 1 2 3 4 5 6 Double array: 1.1 1.2 1.3 String array: Nice to meet you.
  • 13.
    • When thecompiler translates the generic method printArray into Java bytecodes, it removes the type parameter section and replaces the type parameters with actual types. This process is known as erasure. • By default all generic types are replaced with type Object. • So the compiled version of method printArray is: public static void printArray( Object[] Arr) { for (int count=0; count<Arr.length; count++) System.out.printf( "%s ", Arr[count]); System.out.println(); } • There is only one copy of this code that is used for all printArray calls in the example. This is quite different from other, similar mechanisms, such as C++'s templates in which a separate copy of the source code is generated and compiled for every type passed as an argument to the method.
  • 14.
    • We’ve eliminatedthe need for the overloaded methods of, saving 20 lines of code. • We’ve created a reusable method. • The printArray example could have been written by using an array of Objects as a parameter. This by using an array of Objects as a parameter. This would have yielded the same results because any Object can be output as a String. • The benefits become apparent when the method also uses a type parameter as the method's return type, as we will soon see.
  • 15.
    • Example: iterativebinary search public static <T extends Comparable> int binarySearch(T[] Arr, T key ) { int low = 0; int high = Arr.length - 1; int mid; while( low <= high ) { mid = ( low + high ) / 2; if(Arr[ mid ].compareTo(key)< 0) low = mid + 1; low = mid + 1; else if(Arr[ mid ].compareTo(key)> 0) high = mid - 1; else return mid; } return -1; }
  • 16.
    • Declaring ageneric method with a return type that finds the maximum of an array of an arbitrary class that implements the interface Comparable: public static <T extends Comparable> T Max(T[] Arr) { T max=Arr[0]; for(int c=0;c<Arr.length;c++) if(max.compareTo(Arr[c])<1) if(max.compareTo(Arr[c])<1) max=Arr[c]; return max; } • T extends Comparable means that only objects of classes that implement interface Comparable can be used with this method.
  • 17.
    • The interfaceComparable imposes a total ordering on the objects of each class that implements it. • Note that type parameter declarations that bound the parameter always use keyword extends regardless of whether the type parameter extends a class or implements an interface. • A benefit of implementing the interface Comparable is that Comparable objects can be used with the sorting (e.g., Selection sort) and searching (e.g., binary search) algorithms that are based on comparing objects.
  • 18.
    public static voidmain(String args[]) { String s[]={"Cc", "Dw", "Ma", "Ad"}; Integer a[]={1, 2, 3, 44, 0}; Double d[]={1.1, 1.2, 66.3, 44.1, 23.44}; System.out.println("Max of String array is “ + Max(s)); System.out.println("Max of Integer array is "+ Max(a)); System.out.println("Max of Double array is “ + Max(d)); } • The output is: • The output is: Max of String array is Ma Max of Integer array is 44 Max of Double array is 66.3
  • 19.
    • We couldn’thave written the method Max by using class Object, simply because, class Object does not implement the interface Comparable, thus, it does not have a compareTo method, in the sense that comparing is not meaningful for all kinds of objects.
  • 20.
    Overloading generic methods •A generic method may be overloaded; a class can provide two or more generic methods that specify the same method name but different method parameters. • A generic method can also be overloaded by non- generic methods that have the same method name and number of parameters. • When the compiler encounters a method call, it • When the compiler encounters a method call, it performs a matching process to determine which method to invoke. • A precise match is the aim; in which the method names and argument types of the method call match those of a specific method declaration. If there is no such method, the compiler determines whether there is an inexact but applicable matching method.
  • 21.
    Generic Classes Classes CanTake Parameters Classes Can Take Parameters
  • 22.
    • The conceptof a data structure (e.g., a stack) can be understood independently of the type of elements it manipulates. • Generic classes provide a means for describing the concept of a class in a type-independent manner. • We can then instantiate type-specific objects of the generic class. the generic class. • For example, a generic Stack class could be the basis for creating many Stack classes (e.g., "Stack of Double," "Stack of Integer," "Stack of Character," "Stack of Employee," etc.). • Generic classes provide a wonderful opportunity for software reusability.
  • 23.
    • Example: ageneric linked list class class Node<T> { public T Data; public Node Next; public Node(T data) { Data=data; Data=data; } public void DisplayData() { System.out.println(Data+" "); } }
  • 24.
    class GenericLinkedList<T> { public Node<T>First; public GenericLinkedList() { First=null; } public void Insert(T key) { Node<T> New=new Node<T>(key); New.Next=First; First=New; } public T Find(T key) public T Find(T key) { Node<T> Current=First; while(!Current.Data.equals(key)) { if(Current.Next==null) return null; else Current=Current.Next; } return Current.Data; } … Next slide
  • 25.
    public void DisplayList() { Node<T>Current=First; while(Current!=null) { Current.DisplayData(); Current=Current.Next; } System.out.println(); } } //end of class GenericLinkedList<T>
  • 26.
    import java.math.BigInteger; class Test { publicstatic void main(String args[]) { GenericLinkedList <BigInteger> ListBigInteger=new GenericLinkedList<BigInteger>(); GenericLinkedList <Integer> ListInteger=new GenericLinkedList<Integer>(); for(int c=1;c<=10;c++) ListBigInteger.Insert(BigInteger.TEN.pow(10*c)); ListBigInteger.Insert(BigInteger.TEN.pow(10*c)); for(int c=1;c<=15;c++) ListInteger.Insert(c); System.out.println("BigInteger list:"); ListBigInteger.DisplayList(); System.out.println("Integer list:"); ListInteger.DisplayList(); … Next slide
  • 27.
    BigInteger B=ListBigInteger.Find(BigInteger.TEN.pow(10*3)); if(B==null) System.out.println(BigInteger.TEN.pow(10*3)+" isnot found in ListBigInteger."); else System.out.println(BigInteger.TEN.pow(10*3)+" is found in ListBigInteger."); Integer N=ListInteger.Find(5); if(N==null) System.out.println(5+" is not found in ListInteger."); System.out.println(5+" is not found in ListInteger."); else System.out.println(5+" is found in ListBigInteger."); } } //end of class Test
  • 28.
    • The outputis: BigInteger list: 10000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000 10000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000 10000000000000000000000000000000000000000000000000000000000000000 0000000000000000 10000000000000000000000000000000000000000000000000000000000000000 000000 000000 1000000000000000000000000000000000000000000000000000000000000 100000000000000000000000000000000000000000000000000 10000000000000000000000000000000000000000 1000000000000000000000000000000 100000000000000000000 10000000000
  • 29.
  • 30.
  • 31.
    import java.util.ArrayList; public classWildcards { public static void main(String args[]) { ArrayList<Number> Arr=new ArrayList<Number>(); for(int c=0;c<9;c++) { Arr.add(new Integer(c)); Arr.add(new Double(1.1*c)); } } Print(Arr); } public static void Print(ArrayList<Object> A) { for(Object N: A) System.out.println(N); } } • Pop quiz: will the previous program compile?
  • 32.
    • No, itwon’t compile. Here is the compilation error message: Method Print in class Pack.Wildcards can not be applied to given types required: java.util.ArrayList<java.lang.Object> found: java.util.ArrayList<java.lang.Integer> • Translation: You might expect that method Print would also work for ArrayLists that contain elements of any type, such as ArrayList< Integer>. The that contain elements of any type, such as ArrayList< Integer>. The problem is that ArrayList<Object> is not considered to be a supertype of all kinds of ArrayLists.
  • 33.
    Thanks for listening/viewing Feelfree to send any comments or suggestions Presentation by: Muhammad Alhalaby Email: muhammad.alhalaby@gmail.com