/
Generics We have already seen Generics, let’s examine why we use them Generics We have already seen Generics, let’s examine why we use them

Generics We have already seen Generics, let’s examine why we use them - PowerPoint Presentation

MsPerfectionist
MsPerfectionist . @MsPerfectionist
Follow
342 views
Uploaded On 2022-08-03

Generics We have already seen Generics, let’s examine why we use them - PPT Presentation

In using an ArrayList we specify lt Type gt to indicate the type of Object that the ArrayList will store this is known as a Generic Type or Generics lt Type gt is known as the ID: 933498

class type box generic type class generic box public return comparable method object extends arraylist string compareto integer number

Share:

Link:

Embed:

Download Presentation from below link

Download Presentation The PPT/PDF document "Generics We have already seen Generics, ..." is the property of its rightful owner. Permission is granted to download and print the materials on this web site for personal, non-commercial use only, and to display it on your personal computer provided you do not modify the materials and that you retain all copyright notices contained in the materials. By downloading content from our website, you accept the terms of this agreement.


Presentation Transcript

Slide1

Generics

We have already seen Generics, let’s examine why we use them

In using an

ArrayList

, we specify <

Type

> to indicate the type of Object that the

ArrayList

will store

this is known as a Generic Type, or Generics

<

Type

> is known as the

type parameter

the <> is sometimes called the

diamond notation

Generics were first introduced in Java with version 1.5

They are roughly based on a C++ concept called templates

We do not necessarily need Generics as instead we could always declare a variable to be of type Object, but then we would have to perform casting or

downcasting

of the object, Generics is cleaner

Slide2

ArrayList

We have seen that the

ArrayList

can be used to store any type of Object

We can either declare an

ArrayList

without a specific type (this would be using the

ArrayList

pre Java 1.5) or we can declare the

ArrayList

using Generics – with Generics, it cuts down on the need to perform casting

ArrayList

names=new

ArrayList

( );

String temp=(String)

names.get

(

i

);

Without the cast, we get syntax errors and even with the cast we may get a compiler warning (requiring that we use @

Suppresswarnings

)

By creating a Generic type, we avoid having to cast the result

ArrayList

<String> s=new

ArrayList

<String>( );

s.add

(“Susan”);

String s2 =

s.get

(0);

Slide3

Declaring a Generic Type

We allow the user program to specify the type to be used

for a container class so

that, when

the container class itself is written, there is no commitment

to the type

being stored (as

long as the type is an

object of some kind)

ArrayList

<Integer>

myints

=new

ArrayList

<Integer>();

ArrayList

<Tank>

mytanks

=new

ArrayList

<tank>();

Generics permit stronger type checking to reduce the number of possible run-time errors that might

arise when the user is dealing with Objects

We can also write our own Generic classes

We will also be examining several Java container classes (in the next couple of chapters) that were defined using Generics to give us greater flexibility in their usage

Slide4

Comparing

ArrayList

and

ArrayList

<E>

Slide5

Defining a Generic Class

To indicate that a class we are writing is generic, add <

placeholder

> to the class header after the class name

The placeholder is usually a single letter, using the following naming convention

E – used with Java container types like

ArrayList

K, V – used for Key and Value (when you have a Key-Value pair)

N – used if the type is to be restricted to a numeric type of Object

T – generic Type

Example:

public class

MyGenericClass

<T> {…}

In your class, use T as the type to declare whatever instance datum is necessary

private T foo;

To create a variable of a Generic class, you must the type in the declaration as in

MyGenericClass

<Integer>

myInt

;

Slide6

Simple Example: Boxing

Recall that for all primitive types, we have equivalent Classes that “box” the type so that we can treat a datum of a primitive type as an Object

Let’s create a generic Box class to box any Object

We might do this so that the programmer who wishes to utilize different types of objects will not have to use casts

What should a Boxing class have?

It needs to store the object itself

We need an

accessor

(get) and

mutator

(set)

We might also implement a

toString

Slide7

public class Box<T

> {

private T

item;

public

Box(T item

) {

this.item

=item;

}

public

T get

() { return item; } public void set(T item) { this.item=item; } public String toString() { if(item!=null) return ""+item; else return "not set"; }}

Our box class is very basicThe type of Object is recorded as T (filled in when you declare a variable of type Box)T is used to specify the type for item when declared as an instance datum, or passed asa parameter to a method or returned from a methodNote that T needs to have atoString implemented or this returns the address of item

Slide8

public class

BoxUsers

{

public

static void

main(

String

[]

args

) {

Box<String

> a;

Box<Integer> b; Box<Double> c; Box<Object> d=null; a=new Box<>("hi there"); b=new Box<>(100); c=new Box<>(100.1); System.out.println(a.get()); a.set("bye bye"); c.set(c.get()+1); System.out.println(a); System.out.println

(c); System.out.println(d); }}Output:hi therebye bye101.1nullWhat if we want to do

c.set

(

b.get

( )+1);This yields an error because b.get( ) returns an Integer and c.set expects a Double, so instead use c.set(new Double(b.get( )+1));

Slide9

import

java.util

.*;

public

class

GenericStack

<E> {

private ArrayList<E> stack;

public

GenericStack

(){

stack=new

ArrayList

<E>(); } public int getSize() { return stack.size(); } public E peek() { return stack.get(stack.size()-1); } public E pop() { E returnItem=stack.get(stack.size()-1); stack.remove(stack.size()-1); return

returnItem; } public void push(E newItem) { stack.add(newItem); } public boolean isEmpty() { return stack.isEmpty(); }}A Generic

Stack Class

GenericStack

<String> stack=

new GenericStack<>();stack.push(“string1”);stack.push(“string2”);…

Slide10

Bounded Generic Classes

We can restrict the types acceptable in a Generic class by “bounding” the generic class using

public class

Name

<

placeholder

extends

Type>Where Type

is the type we want to restrict our Generic classes to, such as Number

We might want a Box-like generic which is limited to Numeric Objects

we would employ <T extends Number>

public class

NumericBox

<T extends Number> { T item; public NumericBox(T item){this.item=item;} public boolean bigger(T item2){ if(item.doubleValue()>item2.doubleValue()) return true; else return false; }}

Slide11

Example: Unique Pair Class

Let’s expand on the Box example by implementing a Generic class which stores 2 items of the same type of Object

In this case, we want to make sure that the two items (instance data) are unique

Arbitrarily, we will decide that if the two items are equal (as determined by Comparable), the second of the two will be set to null

To test for uniqueness, we need to have Comparable implemented on the class of the

Objects

How can we ensure that the class being utilized implements Comparable

?

We need to state that the type, T, implements Comparable by specifying <T extends Comparable<T>>

Slide12

public class

UniquePair

<T extends Comparable<T

>> {

private

T item1, item2;

public

UniquePair(T i1, T i2

){

item1=i1;

item2=i2;

if(item1.compareTo(item2)==0) item2=null;

} public T get1() { return item1; } public T get2() { return item2; } public void set1(T i1) { item1=i1; if(item1.compareTo(item2)==0) item2=null; } public void set2(T i2){ item2=i2; if(item1.compareTo(item2)==0) item2=null; } }UniquePair

<Integer> a=new UniquePair<>(new Integer(10), new Integer(20));a.set1(new Integer(20)); results in object a storing (20, null)

Slide13

Generic Classes with More than 1 Type

UniquePair

had 2 instance data of the same type

What about a Generic class of multiple types?

The common example is a Key-Value pair, sometimes called a tuple

The idea is that we are storing an attribute’s name and the value of that attribute

a person can be described using multiple key-value pairs such as “Name: Frank Zappa”, “Occupation: Musician”, “Height: 70 inches”,

etc

Let’s implement a Key-Value pair which has methods to determine if another Key-Value pair has the same Key and Value

Through Comparable, we compare both Keys and both Values

Slide14

public class

KeyValuePair

<K extends Comparable<K>,V

extends Comparable<V>> {

private

K

key;

private

V value;

public

KeyValuePair

(K k2, V v2) {key=k2;value=v2;} public K getKey(){return key;} public V getValue(){return value;} public void setKey(K k2){key=k2;} public void setValue(V v2) {value=v2;}

@SuppressWarnings("unchecked") public boolean equal(KeyValuePair kvp){ if(key.compareTo((K)kvp.getKey())==0&& value.compareTo((V)kvp.getValue())==0) return true; else return false; }

}

NOTE: The Java compiler

d

oes not like the compareTo operations and so we have to suppress a warning to ensureproper compilation

Slide15

@

SuppressWarnings

("unchecked")

public

static void main(String[]

args

){

KeyValuePair

<

String,Integer

>

k1=new

KeyValuePair("Height", 71); KeyValuePair<String,Integer> k2=new KeyValuePair("Height", 69); System.out.println(k1.equal(k2));}Here, the Java compilerdoes not like the equaloperation and so weh

ave to suppress a warning to ensureproper compilationpublic class KeyValuePair<K extends Comparable<K>,V extends Comparable<V>>Let’s take a closer look at the class’ headerAside from <K, V> we say that both extend

Comparable and add Comparable<K> and

Comparable<V> so that

compareTo

expects a KeyValuePair<K,V>

Slide16

Raw Types

In some cases, you can omit the <Type> when declaring a variable of a Generic type – this is known as a raw type

ClassName

variable=new

Classname

();

This is available for Generic classes which were originally defined in Java prior to the inclusion of Generics in Java (pre Java 1.5), such as

ArrayList

or classes that implement a Generic interface like Comparable

This allows us to maintain backward compatibility

Raw types are unsafe and result in unchecked warnings generated by the Java compiler resulting in the program not compiling

You can use a different compiler setting to avoid unchecked warnings

We can also avoid the unchecked warnings by suppressing them by placing the following compiler directive before any method that might cause this warning

@Suppresswarnings(“unchecked”)

Slide17

Implementing Comparable

Interfaces themselves can be generic when written

If we want our Generic class to implement an interface, then we have to make sure we implement the proper method(s) for the interface

Let’s implement Comparable for our Box class

If we have two Box objects, compare them using

compareTo

The problem is that we can’t just implement our own

compareTo

method that somehow tests the internal portions of our Object because we may not have access to those Objects’ instance data

But as we saw, we can ensure that the Objects are Comparable by using <T extends Comparable<T>>

Since T is Comparable, we can then implement our own

compareTo

method which calls T’s

compareTo method

Slide18

Implementing a Comparable Box

The class header is now more complicated as not only does T extend Comparable, but this class implements Comparable<T>

public class

ComparableBox

<T extends Comparable<T>> implements Comparable<T>

We have to implement

compareTo

recall

compareTo

expects to receive an Object but this will be utilized in a setting like this:

ComparableBox

<T>

foo.compareTo

(ComparableBox<T> bar)we have to “strip out” the T object from bar before we can compare it to foo’s T object and so we wind up writing two compareTo methods

Slide19

public class

ComparableBox

<T extends Comparable<T>> implements Comparable<T

> {

T item;

// ... as before

public int

compareTo

(

ComparableBox

<T> item2)

{

return compareTo(item2.get()); } @Override public int compareTo(T item2) { return item.compareTo(item2); }}Invoked by code like this:ComparableBox<String> a=new ComparableBox<>("hi there");ComparableBox<String> b=new ComparableBox<>("bye bye");System.out.println(a.compareTo(b));

Slide20

A Generic Matrix Class

The book covers a Generic Matrix Class

A Matrix is a 2-D array

The type of value to be stored will be Generic

We often perform arithmetic operations on matrices so we will restrict the Generic type to extend Number

The author implements

GenericMatrix

as an abstract class requiring that subclasses implement the abstract methods

Why? Some operations will have to be implemented differently based on type

So for instance, an Integer version might implement an add method one way while a

RationalNumber

version would use a different approach

But at the same time, other operations like

copyMatrix and printMatrix can be implemented strictly with the Generic typesee details on pages 785-789

Slide21

Generic Methods

We can write

static

methods which receive a Generic type of parameter rather than a specifically typed parameter

We could also receive an Object, but that may require casting and if we need to use an object of the same type in the method, we wouldn’t know which type to use or to cast

Structure of a Generic method header:

public static <type>

returntype

name(

params

){…}

To invoke a Generic method, much like creating a variable of a Generic class, you need to specify the type in the method call as in

SomeClass

.<type>methodName(params);As with Generic classes, you can bound the type using <Type extends Class> and use multiple types as in <String,Integer>

Slide22

public static <E extends Comparable<E>> void sort(E[] list)

{

E min;

int

minIndex

;

for(int

i

=0;i<list.length-1;i++) {

min=list[

i

]; minIndex=i; for(int j=i+1;j<list.length;j++) { if(min.compareTo(list[i]>0) { min=list[j] minIndex=j; } } list[minIndex]=list[i]; list[i]=min;

}}Generic Selection SortThis selection sort can be called with any array of some Comparable Objects whether that is String, Character, Integer, Double, etcAssume this is placed in a class calledGenericSortClass and we have anObject of this type called fooCall the function with

foo.<Integer>sort(

intArray

);

Or from within GenericSortClass assort(intArray);

Slide23

Wildcard Types

Recall the

NumericBox

bounded our Box’s Object to be a subclass of Number, but we don’t have to resort to bounding the class itself

Instead, we can place a bound on the parameter type allowed for a generic method

Let’s see how to create a “

greaterThan

” method for two Boxes where we expect the Box types to be Numeric (e.g., Box<Number>)

We employ another Generic mechanism called a

wildcard

wildcards are only allowed in static methods

As a static Generic method will only operate on parameters and not non-static instance data, we will pass both objects to be operated on to this method

Slide24

Enhancing Box with a Wildcard

First, we go back to our Box class without having <T extends Number>

So this is just an ordinary Box class in which any Object type can be used to declare an object such as

Box<String> b1;

Box<Integer> b2;

Box<Student> b3; // assumes we have a Student class

But if we want to implement a

greaterThan static method, we need to make sure that the type (String, Integer, Student) is Comparable – in our case we will restrict it even further to be a Number type

So our

greaterThan

static method will bound the type and not the Box class itself

Slide25

Bounding with a Wildcard

The notation for our static method is similar to our previous example of a static method (although in this case, we are receiving 2 parameters, not one)

Instead of the two Box parameters being <T>, we use <? extends Number> to indicate any class/subclass of Number

public

static <T>

boolean

greater(Box<? extends Number> item1,

Box

<? extends Number> item2

)

{

if(item1.get

().

doubleValue()>item2.get().doubleValue()) return true; else return false;}Box<String> a=new Box<>("Hi there");Box<Integer> b=new Box<>(12);Box<Double> c=new Box<>(11.5);System.out.println(Box.greater(a,c));System.out.println(Box.greater(b,c

));Causes a syntax error becauseobject a (Box<String>) is not a subtype of Numberwe use double since it is the widest numeric type(any numeric type can be converted to a double)

Slide26

Another Example

Returning to our previously written

GenericStack

, we create a multiply method

We can only multiply Numbers

We will multiply pairwise values of two

GenericStacks

, adding each product together and return the result as a double since double is the widest type of Number

public

static

<E> double

multiply(

GenericStack

<? extends Number> s1, GenericStack<? extends Number> s2) { double temp=0; int smaller=s1.getSize(); if(s2.getSize()<smaller) smaller=s2.getSize(); for(int i=0;i<smaller;i++) temp=s1.pop().doubleValue()*s2.pop().doubleValue(); return temp;}

Slide27

Continued

Now let’s write a method to multiply all pairs of the Stack, creating a new Stack (e.g., top element of the new Stack is the top of s1 * top of s2,

etc

, the method will return a Stack

Our method header would look like this:

public static

<E>

GenericStack

<

sometype

>

multiplyStacks

(GenericStack<? extends Number> s1, GenericStack<? extends Number> s2)But what type of GenericStack should the method return? What Java does not allow is a return type of ObjectType<?> - that is, we cannot use the wildcard character in the return type anywhere, we must specify an exact type

Slide28

Continued

For our return type, let’s re-examine the previous multiply method

We used double as the return type, why? Because it is the widest numeric type (aside from

BigInteger

and

BigDecimal

)

No matter what numeric type is used for s1 and s2, we can coerce them into doublesSo we will use

GenericStack

<Double> as our return type

public

static

<E>

GenericStack<Double> multiplyStacks (GenericStack<? extends Number> s1, GenericStack<? extends Number> s2) { GenericStack<Double> temp=new GenericStack<>(); int smaller=s1.getSize(); if(s2.getSize()<smaller) smaller=s2.getSize(); for(int i=0;i<smaller;i++) temp.push

(s1.pop().doubleValue()*s2.pop().doubleValue()); return temp;}

Slide29

More on Wildcards

If you want to reference any type of object, use <?>

known as an

unbounded

wildcard

If you want to reference any type of object at or lower than a given class, use <? extends

class

>known as an upper boundnote that <?> is equal to <? extends Object>

If you want to reference any type of object at or higher than a given class, use <? super

class

>

known as a lower bound

you would use a lower bound if there were specific subclasses that you wanted to

prohibit from being usable as parametersNote that while parameters of a generic method can use wildcards, if the method is to return a generic type, it must be specified (e.g., as T) and not use a wildcard

Slide30

Type Erasure

Generic types are filled in by the compiler as the compiler converts your Java code

Thus, at run time, all Generic types are actually converted into raw types

This is because you

must

specify the type to be used in a Generic class when you declare your variable

Box<Integer> b1 =

… causes a Box type to be implemented with Integer as the type (for all occurrences in Box of T)

Box<String> b2 =

… causes a Box type to be implemented with String

Once compilation is over, the “generic” aspect of the class is erased, now the object contains a specific type

Thus, you cannot apply a generic at run time, only at compile time

This idea is known as type erasure

Slide31

Restrictions on Generics

You cannot create an instance of a variable using a Generic type using new as in

E foo=new E( );

You will only be able to assign foo to a parameter of type E as in

public

MyClass

(E bar) {E foo=bar;}

You cannot create an array of a Generic type as in

E[ ] foo=new E[100];

There are ways to get around this, for instance creating an

ArrayList

of type E as in

ArrayList

<E> foo=new ArrayList<>();or by creating an array of objects and casting as in E[] foo=(E[])new Object[100]; although this solution causes an unchecked warning

Slide32

Restrictions Continued

You cannot create a Generic using a primitive

type as in

Box<int> b1=

When using a generic method, since it has to be static, it cannot access non-static members of your class

Instead, think of the method as only operating on parameters

Similarly, you cannot declare a static variable to be of a Generic type

You cannot use casts or

instanceof

on a parameterized type

You cannot create parameterized Exceptions

you can use a parameterized type in a throws clause

You cannot overload methods with parameterized types