Lec_17_18_v2
Lec_17_18_v2
2
Dr. Muhammad Ibrahim
Generics
● Can be defined as parameterized types.
● Using it we can define class, interface, methods that take the type of
the data to operate on as parameter.
○ So it is possible to define a single class that works for different types of
data.
● A class, interface or method that operates on a generic data type is
called generic class, generic interface and generic method
respectively.
3
Dr. Muhammad Ibrahim
Example of a Generic Class
class Gen<T> { Gen<Integer> iOb = new Gen <Integer>(88);
T ob;
Gen(T o) { Gen<String> strOb = new Gen <String>("Test");
ob = o;
}
T getob() {
return ob;
}
void showType() {
System.out.println("Type
of T is " +
b.getClass().getName());
}
}
4
Dr. Muhammad Ibrahim
Details
● class Gen<T> {
○ T is called the type parameter
○ Gen is a generic class, which is also called a parameterized type.
● T ob;
○ Declare an object of type T
○ T is a placeholder for the actual type that will be specified when a Gen object is created.
○ Thus, ob will be an object of the type passed to T.
● Gen(T o) { ob = o; }
○ T can be passed as parameter
● T getob() { return ob; }
○ T can be used as return type
5
Dr. Muhammad Ibrahim
Details (Contd.)
● The getClass() method is defined by Object and is thus a member of
all class types (because all classes inherit Object).
○ It returns a Class object that corresponds to the type of the class of the
object on which it is called.
○ The Class object defines the getName() method, which returns a string
representation of the class name.
● Gen<Integer> iOb;
○ A version of Gen for Integers is created.
○ Integer is a type argument that is passed to Gen’s type parameter, T.
6
Dr. Muhammad Ibrahim
A Few Points
● Generic class mechanism doesn’t work with primitive types.
○ Gen<int> intOb = new Gen<int>(53); // Error, can't use primitive type.
● Generic objects are not type-compatible with each other, i.e., a reference
variable of one type of a generic is not type-compatible with a reference
variable of another type of the same generic class.
○ Gen<Integer> intOb = new Gen<Integer>(53);
○ Gen<String> strOb = new Gen<String>(“text”);
○ iOb = strOb; //ERROR, even though both have Gen<T>
● Autoboxing and auto-unboxing work frequently with generics
○ Gen<Integer> intOb = new Gen<Integer>(53);is equivalent to
Gen<Integer> intOb = new Gen<Integer>(new Integer(53));
○ Similarly, int v = iOb.getob(); is equivalent to int v =
iOb.getob().intValue();
7
Dr. Muhammad Ibrahim
Generics and Type Safety
● Since Object is a superclass of all classes, and since a superclass reference
variable can refer to any subclass object, we can already use variables of
type Object in a class to make the class accept all types of data (such as
Integer, Double etc.)
○ However, type safety cannot be achieved using this scheme.
● Without generics we need to explicitly cast to produce type-safe code.
● With generics we no longer need to cast explicitly - all casts are automatic
and implicit.
● So what exactly is type safety? Let’s wait a few slides to get to the answer!
8
Dr. Muhammad Ibrahim
So What’s the Benefit of Using Generic?
● Using Object would apparently do the same job as using Gen
class.
● However, explicit type-cast would be needed.
● Take a look at the next slide…
9
Dr. Muhammad Ibrahim
An Alternative to Generic Class?
Gen iOb = new Gen(88);
Gen strOb = new Gen("Test");
class Gen {
Object ob;
Gen(Object o) {
However, we can no longer write:
ob = o; int v = iOb.getob();
} String s = strOb.getob();
Object getob() {
return ob;
Instead, we must write:
}
int v = (int)iOb.getob();
void showType() {
String s =
System.out.println("Type of T is " +
(String)strOb.getob();
ob.getClass().getName());
}
}
10
Dr. Muhammad Ibrahim
Benefits of Generics
● Thus, generics relieves the programmers from a lot of explicit type-casting.
● Moreover, generics alleviates some runtime errors.
○ Using the previous scheme of using Object, the following compiles but is
conceptually wrong:
■ iOb = strOb;
■ v = (Integer) iOb.getob(); // run-time error! Because iOb is now a String.
○ Whereas when using generics, iOb = strOb; produces compile time error,
which is definitely better than runtime error.
● The bottom line: although it is always possible to produce a code of generics
into a code that uses Object class, (1) it will not be type-safe, and (2) it may
incur some runtime errors.
11
Dr. Muhammad Ibrahim
Generic Class with Two Type Parameters
class TwoGen< T, V> { V getob2() {
T ob1; return ob2;
V ob2; }
TwoGen(T o1, V o2) { }//class TwoGen
ob1 = o1;
ob2 = o2; class SimpGen {
} public static void main(String
void showTypes() { args[]){
System.out.println("Type of T TwoGen<Integer, String> tgObj =
is " + ob1.getClass().getName()); new TwoGen<Integer, String>(88,
System.out.println("Type of V "Generics");
is " + ob2.getClass().getName()); tgObj.showTypes();
} int v = tgObj.getob1();
T getob1() { System.out.println("value: " + v);
return ob1; String str = tgObj.getob2();
} System.out.println("value: " +
str); 12
Dr. Muhammad Ibrahim
Generic Class with Two Type Parameters
● Thus, we can define generic classes with as many variables as
required.
● In the previous example, it is possible to write:
TwoGen<Integer, Integer> Obj = new TwoGen<Integer, Integer>(88, 89);
13
Dr. Muhammad Ibrahim
General Form of Generics
● Declaring a generic class: class class-name<type-param-list> {
● Declaring a reference to a generic class and instance creation:
class-name<type-arg-list> var-name =
new class-name<type-arg-list>(cons-arg-list);
14
Dr. Muhammad Ibrahim
Bounded Types
● Preceding examples showed the scenario where any data type can be used to
create specific instances of generic classes.
● While this is allowed in some applications, some other applications warrant that
we restrict the creation of instances of generic class to some data types only.
○ Consider an application that returns the average of the values of an array of numbers
(integers, floating point numbers etc.).
○ So this application, when using generics, must ensure that only numbers are used to
create instances of the generic class.
○ Recall that all numeric classes (Integer, Double etc.) are subclasses of class
Number.
15
Dr. Muhammad Ibrahim
Bounded Types Example
class Stats<T> { class Stats<T> {
T[] nums; T[] nums;
Stats(T[] o) { Stats(T[] o) {
nums = o; nums = o;
} }
// Return type double in all cases. // Return type double in all
double average() { cases.
double sum = 0.0; double average() {
for(int i=0; i < nums.length; i++) double sum = 0.0;
sum += nums[i]; for(int i=0; i < nums.length;
return sum / nums.length; i++)
} sum +=
} nums[i].doubleValue();
return sum / nums.length;
}
} 16
Dr. Muhammad Ibrahim
Bounded Types Example
class BoundsDemo {
public static void main(String
class Stats<T extends Number > {
args[]){
T[] nums;
Integer inums[] = { 1, 2, 3, 4, 5 };
Stats(T[] o) {
Stats<Integer> iob =
nums = o;
new Stats<Integer>(inums);
}
double v = iob.average();
// Return type double in all cases.
System.out.println("iob average is "
double average() {
+ v);
double sum = 0.0;
Double dnums[] = { 1.1, 2.2, 3.3,
for(int i=0; i < nums.length;
4.4, 5.5 };
i++)
Stats<Double> dob =
sum +=
new Stats<Double>(dnums);
nums[i].doubleValue();
double w = dob.average();
return sum / nums.length;
System.out.println("dob average is "
}
+ w);
}//class Stats
}
17
Dr. Muhammad Ibrahim
}//class BoundsDemo
Bounded Types Example
Output:
Average is 3.0
Average is 3.3
18
Dr. Muhammad Ibrahim
Having Both Class and Interface as Bound Types
● In addition to using a class type as a bound, we can also use an interface type.
○ In fact, we can specify multiple interfaces as bounds.
● Furthermore, a bound can include both a class type and one or more interfaces.
○ In this case, the class type must be specified first.
● Bottom line: at most one class can be included as bound type, although more than
one interface can be used, and both class and interfaces can be used
simultaneously.
● When a bound includes an interface type, only type arguments that implement that
interface are legal.
19
Dr. Muhammad Ibrahim
Having Both Class and Interface as Bound Types
● When specifying a bound that has a class and an interface, or multiple
interfaces, use the & operator to connect them.
○ class Gen<T extends MyClass & MyInterface> { // …
○ Here, T is bounded by a class called MyClass and an interface called
MyInterface.
○ Thus, any type argument passed to T must be a subclass of MyClass
and must implement MyInterface.
20
Dr. Muhammad Ibrahim
End of Lecture 17.
21
Dr. Muhammad Ibrahim
Topics
Generics
Generic class: syntax and benefit
Bounded types with classes and interfaces
Wildcards, bounded wildcards
Generic method
Generic interface
Inheritance with generics
Restrictions on generic array
22
Dr. Muhammad Ibrahim
Bounded Types Example
(From Slide 17) class BoundsDemo {
public static void main(String
class Stats<T extends Number > {
args[]){
T[] nums;
Integer inums[] = { 1, 2, 3, 4, 5 };
Stats(T[] o) {
Stats<Integer> iob =
nums = o;
new Stats<Integer>(inums);
}
double v = iob.average();
// Return type double in all cases.
System.out.println("iob average is "
double average() {
+ v);
double sum = 0.0;
Double dnums[] = { 1.1, 2.2, 3.3,
for(int i=0; i < nums.length;
4.4, 5.5 };
i++)
Stats<Double> dob =
sum +=
new Stats<Double>(dnums);
nums[i].doubleValue();
double w = dob.average();
return sum / nums.length;
System.out.println("dob average is "
}
+ w);
}//class Stats
}
23
Dr. Muhammad Ibrahim
}//class BoundsDemo
Wildcards: Motivation
● Suppose in the previous example, we want to add a method called sameAvg() that
determines if two arrays have the same average.
● Example:
boolean sameAvg(Stats<T> ob){
if (this.average() == ob.average()) return true;
else return false;
}
● Will it work? (recall from Eg. given in slide 17 that the type of iob is Stats<Integer> )
Integer inums[] = { 1, 2, 3, 4, 5 };
Double dnums[] = { 1.0, 2.0, 3.0, 4.0, 5.0 };
System.out.println(iob.sameAvg(dob)); // ERROR
24
Dr. Muhammad Ibrahim
Wildcards
● So the problem is, if we use a type parameter T in a generic class, each time it is
substituted by a single data type (Integer or Double etc., but not both at the
same time).
● However, oftentimes we require that T takes different data types for the same
instance.
● Solution: wildcard
boolean sameAvg(Stats<?> ob){
if (this.average() == ob.average()) return true;
else return false;
}
● Now it is valid: System.out.println(iob.sameAvg(dob));
25
Dr. Muhammad Ibrahim
Bounded Wildcards
● Recall the motivation for using bounded types: oftentimes we
want to restrict the allowable types for a generic class.
● For a wildcard too, we may want to restrict the allowable types
for <?> construct.
● It is especially important when a generic involves inheritance.
● Example: next slides…
26
Dr. Muhammad Ibrahim
Example: Bounded Wildcard
class TwoD { // Four-dimensional coordinates.
int x, y; //class FourD extends ThreeD {
TwoD(int a, int b) { int t;
x = a; FourD(int a, int b, int c, int d) {
y = b; super(a, b, c);
} t = d;
}//class ends }
// Three-dimensional coordinates. }//class ends
//class ThreeD extends TwoD {
int z; // This class holds an array of
ThreeD(int a, int b, int c) { //coordinate objects.
super(a, b); class Coords< T extends TwoD > {
z = c; T[] coords;
} Coords(T[] o) { coords = o; }
}//class ends }//class ends
27
Dr. Muhammad Ibrahim
Example: Bounded Wildcard (Contd.)
//to show X and Y coords of an object:
static void showXY( Coords<?> c ) {
System.out.println("X Y Coordinates:");
for(int i=0; i < c.coords.length; i++) Now what if we want to define a method that
System.out.println(c.coords[i].x + " prints X, Y and Z coordinates?
" + c.coords[i].y);
System.out.println(); That is, how can we further restrict the
allowable types, on top of the ones already?
}
29
Dr. Muhammad Ibrahim
Topics
Generics
Generic class: syntax and benefit
Bounded types with classes and interfaces
Wildcards, bounded wildcards
Generic method
Generic interface
Inheritance with generics
Restrictions on generic array
30
Dr. Muhammad Ibrahim
Generic Methods
● Methods inside a generic class work on a type parameter, and
therefore are automatically generic methods.
● It is possible to declare a method inside a generic class that, in
addition to using type parameter, uses some other data types.
● It is also possible to write non-generic methods inside a generic class.
● Equally possible is to define generic methods inside a non-generic
class.
● Next slide: GenMethodDemo.java…
31
Dr. Muhammad Ibrahim
Generic Methods
class GenMethodDemo {
// Determine if an object is in an array.
static <T extends Comparable<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;
}
32
Dr. Muhammad Ibrahim
public static void main(String args[]) {
Recall the main benefit of using generics: preventing type-unsafe codes during
compile time!
35
Dr. Muhammad Ibrahim
Generic Methods: Generic Constructors
class GenCons {
It is possible to write generic private double val;
methods as constructors even <T extends Number> GenCons(T arg) {
though the class is not generic. val = arg.doubleValue();
}
void showval() {
System.out.println("val: " + val);
}
}
class GenConsDemo {
public static void main(String args[]) {
GenCons test = new GenCons(100);
GenCons test2 = new GenCons(123.5F);
test.showval();
test2.showval();
}
36
Dr. Muhammad Ibrahim
}
Generic Interfaces
● Generic interfaces are written just like generic classes.
● Next slide: GenInterfaceDemo.java…
37
Dr. Muhammad Ibrahim
interface MinMax<T extends Comparable<T>> {
T min(); class GenInterfaceDemo {
T max();
} public static void main(String args[]) {
// Now, implement MinMax
class MyClass<T extends Comparable<T>> Integer inums[] = {3, 6, 2, 8, 6 };
implements MinMax<T> { Character chs[] = {'b', 'r', 'p', 'w'};
T[] vals;
MyClass(T[] o) { vals = o; } MyClass<Integer> iob =
// Return the minimum value in vals. new MyClass<Integer>(inums);
public T min() { MyClass<Character> cob =
T v = vals[0]; new MyClass<Character>(chs);
for(int i=1; i < vals.length; i++)
if(vals[i].compareTo(v) < 0) System.out.println("Max value in inums: "
v = vals[i]; + iob.max());
return v; System.out.println("Min value in inums: "
} + iob.min());
// Return the maximum value in vals. System.out.println("Max value in chs: " +
public T max() { cob.max());
T v = vals[0]; System.out.println("Min value in chs: " +
for(int i=1; i < vals.length; i++) cob.min());
if(vals[i].compareTo(v) > 0) }
v = vals[i]; }
return v;
} 38
}
Dr. Muhammad Ibrahim
Generic Interfaces (Contd.)
● If a class implements a generic interface, must that class be a generic too?
● Answer: not necessarily:
○ class MyClass implements MinMax<T> { //Wrong. Here MyClass must be
generic.
○ class MyClass implements MinMax<Integer> { //Valid. Here MyClass is
not generic.
● In a nutshell, two benefits are offered by generic interface:
○ It can work with different types of data.
○ It can put constraints on types of data to be used with it.
39
Dr. Muhammad Ibrahim
Generic Class Hierarchy: Inheriting Generic Class
class Gen<T> {
● Generic classes can be used in class T ob;
hierarchies in the same way as a Gen(T o) {
non-generic class. ob = o;
}
○ Thus, can be a superclass or
// Return ob.
subclass.
T getob() {
● However, the required type information return ob;
must be passed up to all the generic }
classes in a hierarchy. }//Gen class ends
41
Dr. Muhammad Ibrahim
Misc. Topics
Anonymous class
Functional interface
Lambda expression
42
Dr. Muhammad Ibrahim
Anonymous Class
Based on https://www.programiz.com/java-programming/anonymous-class
● Recall that a class can contain another class known as nested class.
● It is possible to create a nested class without giving any name.
● A nested class that doesn't have any name is known as an anonymous class.
● An anonymous class must be defined inside another class. Hence, it is also known as
an anonymous inner class.
● Anonymous classes usually extend subclasses or implement interfaces.
class outerClass {
// defining anonymous class
object1 = new Type(parameterList) {
// body of the anonymous class
};
}
Here, Type can be: a superclass that an anonymous class extends, or an interface that an
anonymous class implements. The above code creates an object, object1, of an anonymous class at
runtime.
43
Dr. Muhammad Ibrahim
Example
class Polygon {
public void display() {
System.out.println("Inside the Polygon class");
}
}
class AnonymousDemo {
public void createClass() {
// creation of anonymous class extending class Polygon
Polygon p1 = new Polygon() {
public void display() {
System.out.println("Inside an anonymous class.");
}
};
p1.display();
}
}
class Main {
public static void main(String[] args) {
AnonymousDemo an = new AnonymousDemo();
an.createClass();
}
} 44
Dr. Muhammad Ibrahim
Example
interface Polygon {
public void display();
}
class AnonymousDemo {
public void createClass() {
class Main {
public static void main(String[] args) {
AnonymousDemo an = new AnonymousDemo();
an.createClass();
}
}
45
Dr. Muhammad Ibrahim
Example (https://docs.oracle.com/javase/tutorial/java/javaOO/anonymousclasses.html#examples-of-anonymous-classes)
● In this example, the method invocation btn.setOnAction specifies what happens when
you select the Say 'Hello World' button.
● This method requires an object of type EventHandler<ActionEvent> .
● The EventHandler<ActionEvent> interface contains only one method, handle.
● Instead of implementing this method with a new class, the example uses an anonymous
class expression.
● Notice that this expression is the argument passed to the btn.setOnAction method.
46
Dr. Muhammad Ibrahim
Benefit of Anonymous Class
In anonymous classes, objects are created whenever they are required.
47
Dr. Muhammad Ibrahim
Functional Interface
In the previous example, EventHandler<ActionEvent> interface contains
only one method, handle.
A functional interface is an interface that contains one and only one abstract
method. Normally, this method specifies the intended purpose of the interface.
Thus, a functional interface typically represents a single action.
48
Dr. Muhammad Ibrahim
Lambda Expression
A lambda expression is, essentially, an anonymous (that is, unnamed)
method.
49
Dr. Muhammad Ibrahim
Lambda Expression
The new operator, sometimes referred to as the lambda operator or the arrow
operator, is –>.
It divides a lambda expression into two parts. The left side specifies any
parameters required by the lambda expression. (If no parameters are needed, an
empty parameter list is used.) On the right side is the lambda body, which
specifies the actions of the lambda expression. The –> can be verbalized as
“becomes” or “goes to.”
50
Dr. Muhammad Ibrahim
Lambda Expression
() -> 123.45 equivalent to double myMethod() { return 123.45; }
(n) -> (n % 2) == 0
51
Dr. Muhammad Ibrahim
Output
52
Dr. Muhammad Ibrahim
Lambda Expression
A lambda expression is not executed on its own. Rather, it forms the
implementation of the abstract method defined by the functional interface
that specifies its target type.
53
Dr. Muhammad Ibrahim
Lambda Expression
interface myNumber{
double getValue();
}
// Create a reference to a MyNumber instance.
MyNumber myNum;
// Use a lambda in an assignment context.
myNum = () -> 123.45;
// Call getValue(), which is implemented by the previously assigned lambda expression.
System.out.println(myNum.getValue());
54
Dr. Muhammad Ibrahim
Lambda Expression
Output
2 is a factor of 10
3 is not a factor of 10
55
Dr. Muhammad Ibrahim
Expression Lambda Vs. Block Lambda
Lambdas that have expression bodies are sometimes called
expression lambdas.
56
Dr. Muhammad Ibrahim
Output
57
Dr. Muhammad Ibrahim
Output
Lambda reversed is
adbmaL
Expression reversed is
noisserpxE
58
Dr. Muhammad Ibrahim
59
Dr. Muhammad Ibrahim
Lambda Expression
A detailed real-life example can be found here:
https://mkyong.com/java8/java-8-lambda-comparator-example/
60
Dr. Muhammad Ibrahim
End of Lecture 18.
61
Dr. Muhammad Ibrahim