Advanced Programming
SUT • Spring 2019
Generic Methods
Generic Classes
Generics and Inheritance
Erasure
public static void printArray(Integer[] intputArray) {
// display array elements
for (Integer element: inputArray)
System.out.println("%s", element);
} // end of printArray
// method printArray to print Double Array
public static void printArray(Double[] intputArray) {
// display array elements
for (Integer element: inputArray)
System.out.println("%f", element);
} // end of printArray
// method printArray to print Character Array
public static void printArray(Integer[] intputArray) {
// display array elements
for (Integer element: inputArray)
System.out.println("%c", element);
} // end of printArray
interface StringStack{
void push(String s);
String pop();
}
interface IntegerStack{
void push(Integer s);
Integer pop();
}
interface StudentStack{
...
}
static void sort(Integer[] array) {
// ...
}
static void sort(Double[] array) {
// ...
}
static void sort(String[] array) {
// ...
}
static void sort(Student[] array){
// ...
}
public static <E> void printArray(E[] intputArray);
Type Parameter
It says: In this method, E is not a regular type, it is a generic one
public static <E> void printArray(E[] inputArray){
// display array elements
for(E element: inputArray)
System.out.println("%s ", element);
System.out.println();
} // end method printArray
// Example
Integer[] integerArray = {1, 2, 3, 4, 5, 6, 7};
Double[] doubleArray = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7};
Character[] characterArray = {'H', 'E', 'L', 'L', 'O'};'
printArray(integerArray);
printArray(doubleArray);
printArray(characterArray);
Restricting possible types
Compile-time type checking
printArray(stringArray) brings
Compiler Error
or exception?
public static <E extends Number> void printArray(E[] inputArray){…}
public static <T extends Comparable<T> > T maximum(T x, T y, T z){
T max = x; // assume x is initially the largest
if (y.compareTo(max) > 0) {
max = y; // y is the largest so far
}
if (z.compareTo(max) > 0) {
max = z; // z is the largest
}
return max; // return the largest object
}
System.out.println(maximum(3, 4, 5));
System.out.println(maximum(6.6, 7.7, 8.8));
System.out.println(maximum("pear", "apple", "orange"));
interface Stack<T>{
void push(T s);
T pop();
}
Stack<String> stringStack = new ...
stringStack.push(“salam”);
String s = stringStack.pop();
public class Stack<E> {
private E[] elements ;
private final int size; // number of elements in the stack
private int top; // location of the top element
public void push(E pushValue) {
if (top == size - 1) // if stack is full
throw new FullStackException();
elements[++top] = pushValue;
}
public E pop() {
if (top == -1) // if stack is empty
throw new EmptyStackException();
return elements[top--];
}
public Stack() {
size = 10;
top = -1;
elements = (E[]) new Object[size];
}
}
Stack<String> stack1 = new Stack<String>();
stack1.push("first");
stack1.push("second");
System.out.println(stack1.pop());
System.out.println(stack1.pop());
Stack<Integer> stack2 = new Stack<Integer>();
stack2.push(1);
stack2.push(2);
System.out.println(stack2.pop());
System.out.println(stack2.pop());
public class Stack<E extends Student> {
private E[] elements ;
private final int size; // number of elements in the stack
private int top; // location of the top element
public void push(E pushValue) {
if (top == size - 1) // if stack is full
throw new FullStackException();
elements[++top] = pushValue;
}
public E pop() {
if (top == -1) // if stack is empty
throw new EmptyStackException();
return elements[top--];
}
public Stack() {
size = 10;
top = -1;
elements = (E[]) new Student[size];
}
}
Generic classes and methods can be used without type parameter
Stack<String> s = new Stack<String>(); // String as type parameter
s.push(“salam”);
s.push(new Integer(12)); // Compiler Error
Stack objectStack = new Stack(); // no type parameter
s.push(“salam”);
s.push(new Integer(12));
s.push(new Student(“Ali Alavi”));
class Stack<T> {
void push(T s){...}
T pop() {...}
}
// Is translated to
class Stack {
void push(Object s){...}
Object pop() {...}
}
public static <T extends Comparable<T> > T maximum(T x, T y, T z);
// translated to:
public static Comparable maximum(Comparable x, Comparable y, Comparable z);
public static <E extends Number> void f(E i){
}
public static void f(Number i){
}
// Compiler Error: Method f(Number) has the same erasure
// f(Number) as another method in this type
A non-generic class can be inherited by a non-generic class
As we saw before learning generics
A generic class can be inherited from a non-generic class
Adding generality to classes
A non-generic class can be inherited from a generic class
Removing generality
A generic class can be inherited by a generic class
class GenericList<T> extends Object{
public void add(T t){...}
public T get(int i) {...}
public void remove(int i) {...}
}
class GenericNumericList<T extends Number> extends GenericList<T>{
}
class NonZeroIntegerList extends GenericList<Integer>{
public void add(Integer t) {
if(t==null || t==0)
throw new RuntimeException(“Bad value");
super.add(t);
}
}
We can also create generic interfaces
No primitives as type parameters
interface Stack<T>{
void push(T s);
T pop();
}
}
class MultipleType<T, K>{
private T t;
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
public void doSomthing(K k, T t){…}
}
MultipleType<String, Integer> multiple =
new MultipleType<String, Integer>();
multiple.doSomthing(5, "123");
You can not instantiate generic classes
Syntax Error: Cannot instantiate the type T
Why?
class Stack<T>{
T ref = new T();
}
You can not instantiate generic classes
Syntax Error: Cannot instantiate the type T
Why?
class Stack<T>{
T[] elements = new T[size];
}
You cannot create a generic array
Syntax Error: Cannot create a generic array of Box<String>
Why?
class Box<T> {
final T x;
Box(T x) {
this.x = x;
}
}
Box<String>[] bsa = new Box<String>[3];
Operations such as instanceof and new are runtime operations
They use a type at runtime
With erasure type information is removed at runtime
So these operations are Meaningless
Although, they may be possible
Older versions:
ArrayList<String> list = new ArrayList<String>();
With Java 7:
ArrayList<String> list = new ArrayList<>();
Type information after new are ignored.
List<Map<Long, Set<Integer>>> list = new ArrayList<>();
Wildcards as type parameters
Java generics vs. C++ templates
Erasure is different in these languages
Type Argument inference
More on erasure
TIJ is so better than Deitel in generics chapter
More Depth
public static void wow(ArrayList<String> list){
Method method = list.getClass()
.getMethod("add", Object.class);
method.invoke(list, new Integer(2));
}
public static void main(String args[]){
ArrayList<String> s = new ArrayList<String>();
wow(s);
for (Object string : s) {
System.out.println(string);
}
}
class A{
public Object f(Object o){
return new Object();
}
}
class B extends A{
public Object f(Object o){
return new String("salam");
}
}
// B.f() overrides A.f()
class A{
public Object f(Object o){
return new Object();
}
}
class B extends A{
public String f(Object o){
return new String("salam");
}
}
// B.f() overrides A.f()
class A{
public Object f(Object o){
return new Object();
}
}
class B extends A{
public Object f(String o){
return new String("salam");
}
}
// B.f() is overloading A.f()
// B.f() does not override A.f()
class Pair<T,K>{
private T first;
private K second;
public Pair(T t, K k) {
this.first = t;
this.second = k;
}
public T getFirst() {
return first;
}
public K getSecond() {
return second;
}
public String toString() {
return "[" + second + ", " + first + "]";
}
}
Pair<Integer, String> pair1 =
new Pair<Integer, String>(4, "Ali");
Integer i = pair1.getFirst();
String s = pair1.getSecond();
Pair<String, Boolean> pair2 =
new Pair<String, Boolean>("salam", true);
String ss = pair2.getFirst();
Boolean bb = pair2.getSecond();
What is wrong with this implementation?
public boolean equals(Pair<T,K> pair) {
return pair.first.equals(first) &&
pair.second.equals(second);
}
It should check for nullity of pair
It should check for nullity of pair.first and pair.second
It should check for nullity of this.first and this.second
This method does not override equals()
It is overloading it
Correct signature:
boolean equals(Object pair)
What if parameter is not a Pair?
public boolean equals(Object o) {
Pair<T, K> pair = null;
try{
pair = (Pair<T, K>) o;
} catch(ClassCastException e){
return false;
}
return pair.first.equals(first) &&
pair.second.equals(second);
}
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Pair other = (Pair) obj;
if(first == null){
if(other != null)
return false;
}else if (!first.equals(other.first))
return false;
if(second == null) {
if (other.second != null)
return false;
} else if (!second.equals(other.second))
return false;
return true;
}