Top Banner
Generics Michael Heron
24

PATTERNS09 - Generics in .NET and Java

Jul 17, 2015

Download

Software

Michael Heron
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: PATTERNS09 - Generics in .NET and Java

GenericsMichael Heron

Page 2: PATTERNS09 - Generics in .NET and Java

Introduction

There is a common technique available in

Java (versions 1.5 and above) and .net

(version 2 and above).

The Generic Datatype

Overloading and polymorphism go a long

way towards making an object oriented

system work ‘properly’

But they only take you to the bridge.

Page 3: PATTERNS09 - Generics in .NET and Java

The Problem

Let’s say we want to create a basic data

structure.

One that works for any object.

It’s something straight forward – a queue,

for example.

How do we do that?

Well, in older versions of a language we’d

declare the data type as an Object.

Page 4: PATTERNS09 - Generics in .NET and Java

The Queue Public class Queue {

ArrayList<Object> myObjects;

void addToQueue (Object ob) {myObjects.add (ob);

}

void removeFromQueue () {Object ob = myObjects.get(0);myObjects.remove (0);return ob;

}}

Page 5: PATTERNS09 - Generics in .NET and Java

The Problem We can use casting to turn whatever is on the

queue into whatever class we need:Person p =

(Person)queue.removeFromQueue();

This is bad OO. It’s not type safe

We need to enforce discipline to make sure that we don’t put the wrong things on the wrong queues. The compiler should be doing as much of that

as is feasible.

Page 6: PATTERNS09 - Generics in .NET and Java

The Solution

Both C# and Java offer the Generic as a

solution.

A class which acts as a type-safe template.

The syntax is a little awkward, but it allows

us to define the type that should be

associated with a data structure.

Like we do with ArrayLists.

Page 7: PATTERNS09 - Generics in .NET and Java

Queue – Java Genericimport java.util.*; public class Queue<T> {

ArrayList<T> myList; public Queue() {

myList = new ArrayList<T>(); } public void addToQueue(T ob) {

myList.add(ob); } public T getFromQueue() {

T ob = myList.get(0); myList.remove(0); return ob;

}

public boolean hasMoreElements() { return (myList.size() != 0);

} }

Page 8: PATTERNS09 - Generics in .NET and Java

Queue – Java Genericpublic static void main(String args[]) {

Queue<String> myQueue = new Queue<String>();

myQueue.addToQueue("Hello!"); myQueue.addToQueue("World!"); while (myQueue.hasMoreElements()) {

System.out.println(myQueue.getFromQueue());

} }

Page 9: PATTERNS09 - Generics in .NET and Java

Queue – C# Genericclass Queue<T>

{

ArrayList myObjects;

public Queue ()

{

myObjects = new ArrayList();

}

public void addToStack<T>(T ob)

{

myObjects.Add(ob);

}

public T removeFromStack()

{

T ob = (T)myObjects[0];

myObjects.RemoveAt(0);

return ob;

}

}

}

Page 10: PATTERNS09 - Generics in .NET and Java

Why Use Generics?

Type safe – we can ensure type incompatibilities are dealt with at the earliest possible opportunity.

Simplifies syntax – no need to cast individual objects.

Allows for effective deployment of certain kinds of design patterns.

Avoids the need for excessive specialisation of classes.

Page 11: PATTERNS09 - Generics in .NET and Java

How do they work?

It is important to know the different ways

in which variables are bound during the

running of an application.

Traditionally variables are bound to a

specific context in one of two ways.

Static binding, which is done at compile

time.

Dynamic binding, which is done at runtime.

Page 12: PATTERNS09 - Generics in .NET and Java

Static Binding

Explicitly indicating the type of a

parameter allows for the compiler to link

objects and variables when compiled.

They’re not going to change in that

respect.

The performance of this is high, and

compile-time checking can be rigorous in

a way that’s not possible otherwise.

Page 13: PATTERNS09 - Generics in .NET and Java

Late Binding

Late binding is used extensively in Java and C#.

One key area in which it is used is in polymorphism.

When you use Polymorphism, Java adopts a late binding approach so that it can properly adapt to the object at runtime.

It knows the most specialised method to use when invoked, but only when the object is bound.

Page 14: PATTERNS09 - Generics in .NET and Java

Strongly Typed Languages In strongly typed languages, early binding is

the norm. We can tell what the context is going to be by

analysing the runtime

However, late binding needs to be dealt with either through polymorphism or compile time casting.

Generics allow for you to defer the binding of a data type until its point of usage arrives. The <T> parameter is unbound.

When we instantiate the class, we bind it to a specific context.

Page 15: PATTERNS09 - Generics in .NET and Java

Boxing and Unboxing

In both Java and C# a related

mechanism is known as autoboxing.

This is the process of converting a value

variable into an object reference, or vice

versa.

When a value reference is boxed, it is

stored on the ‘managed heap’.

A chunk of memory set aside and tended

by the garbage collector.

Page 16: PATTERNS09 - Generics in .NET and Java

Wrapper Classes

Each primitive data type in Java and C#

comes with a corresponding wrapper

class.

A class designed to provide a way of

dealing with it as a reference.

It used to be impossible to have an

ArrayList of ints in Java.

You needed to make them Integer objects

first.

Page 17: PATTERNS09 - Generics in .NET and Java

Wrapper Classes

Autoboxing then is the process at play when a primitive data type is encapsulated within a wrapper.

And vice versa, when it is unwrapped into its primitive form.

Autoboxing is a relatively expensive process.

If you were doing this a lot, it would be worth assessing your specific data manipulation requirements.

Page 18: PATTERNS09 - Generics in .NET and Java

Generics and Constraints

All of this leads to an obvious problem.

What if we don’t want everything to be on

the table for a generic?

Luckily, generics allow us to set constraints

on them.

Limitations that restrict what can be a valid

specification of our class.

There are six types of these in .NET.

Page 19: PATTERNS09 - Generics in .NET and Java

ConstraintsConstraint Description

Where T: struct The type argument must be a value type.

Where T: class The type argument must be a reference

type.

Where T: new() The type argument must have a public,

parameterless constructor

Where T: <class name> The type argument must extend from the

indicated class name.

Where T: <interface

name>

The type argument must implement the

specified interface, or be the interface itself

Where T: U The type argument for T must be or derive

from the argument supplied for U.

Page 20: PATTERNS09 - Generics in .NET and Java

Exampleclass Queue<T> where T : IComparable

{

ArrayList myObjects;

public Queue ()

{

myObjects = new ArrayList();

}

public void addToStack<T>(T ob)

{

myObjects.Add(ob);

}

public T removeFromStack()

{

T ob = (T)myObjects[0];

myObjects.RemoveAt(0);

return ob;

}

public Boolean isInQueue(T ob)

{

T ob2;

for (int i = 0; i < myObjects.Count; i++) {

ob2 = (T)myObjects[i];

if (ob2.CompareTo(ob) != -1) {

return true;

}

}

return false;

}

}

Page 21: PATTERNS09 - Generics in .NET and Java

Constraints

Multiple constraints can be applied to the same parameter.

And in turn, they can be generic in and of themselves.

If you are going to be performing operations on a type that are not defined in Object itself, you need to apply a constraint.

That will allow for the method to be made available in a type-safe way.

Page 22: PATTERNS09 - Generics in .NET and Java

Multiple Parameters

Some classes may provide two types.

For example, Hashtables

T and U are used conventionally to refer

to parameter 1 and parameter 2.

You can apply separate constraints to

each of these:

Where U : class

Where T : iComperable

Page 23: PATTERNS09 - Generics in .NET and Java

Unconstrained Types

With unconstrained types, we have the

following restrictions:

We cannot use simple logical comparators

on them, because there is no guarantee

the concrete type will support them.

They will need to be formally cast.

You can compare to null, but this will

always return false if the type argument is a

value type.

Page 24: PATTERNS09 - Generics in .NET and Java

Conclusion

Generics offer a new and powerful way to deal with type-safe collections.

And other kinds of classes.

Constraints allow us to ensure that we can access useful methods as required.

Polymorphism will ensure that we can reliably access whatever internals we require.

They’re available in both C# and Java.