<<

Generic Classes and Methods: A Deeper Look Week 5- part A

Dr Mohammed Bahja [email protected] https://www.cs.bham.ac.uk/~bahjam/ Before we start

Ø Attendance code of today Ø In-class test ( week 6 –Friday) Ø No WS 4 (you will start the project a week early) Ø Groups for group project. Lecture Objective

To develop a thorough understanding of and how generic classes and methods can be used to provide simpler and elegant solutions Lecture Outline

Ø Objective of generic programming Ø How implement generic classes and methods Ø The execution of generic methods Ø Raw Type and Backward Compatibility Ø Overloading Generic Methods Ø The relationship between generic types and inheritance Ø Wildcards in Methods That Accept Type Parameters Ø Wildcards Types Why Do You Get a Warning?

Ø To understand the compile warning on line 6 & 7, you need to learn generics. The Warning?

ArrayList list = new ArrayList();

list.add("Java Programming"); Compile-time

Ø Detect type mismatches at —known as compile- time type safety. Ø Generic methods and generic classes provide the means to create type safe general models. Overloaded methods

Ø Overloaded methods are often used to perform similar operations on different types of . Ø We can use Overloaded methods to print -for example- arrays of different types. But how many methods you need to create ? Overloaded methods (Cont’) Ø Method for each and Compile-Time Translation Ø If the operations performed by several overloaded methods are identical for each argument type, the overloaded methods can be more conveniently coded using a generic method. Ø You can write a single generic method declaration that can be called with arguments of different types them the handles each method call appropriately. What is Generics?

Ø Generic programming: creation of programming constructs that can be used with many different types. Ø In Java, achieved with inheritance or with type variables Ø The denotes the element type

public class ArrayList // could use "ElementType" instead of { public ArrayList() { . . . } public void add(E element) { . . . } . . . }

Ø You can define a class or a method with generic types that can be substituted using concrete types by the compiler. Why Generics?

Ø The key benefit of generics is to enable errors to be detected at compile time rather than at runtime.

Ø A generic class or method permits you to specify allowable types of objects that the class or method may work with.

Ø If you attempt to use the class or method with an incompatible object, a compile error occurs. Type Variables

Ø Can be instantiated with class or typesArrayList ArrayList

Ø Cannot use a primitive type as a type variableArrayList // Wrong!

Ø Use corresponding wrapper class insteadArrayList Safer and easier to read

package java.lang; package java.lang;

public interface Comparable { public interface Comparable { public int compareTo(Object o) public int compareTo(T o) } }

(a) Prior to JDK 1.5 (b) JDK 1.5

Comparable = new Date(); Comparable c = new Date(); System.out.println(c.compareTo("red")); System.out.println(c.compareTo("red"));

(a) Prior to JDK 1.5 (b) JDK 1.5

Runtime error Compile error Safer and easier to read (Cont’d)

Ø Impossible to add a String into an ArrayList Ø Can add a String into a LinkedList intended to hold bank accounts ArrayList accounts1 = new ArrayList(); LinkedList accounts2 = new LinkedList(); // Should hold BankAccount objects accounts1.add("my savings"); // Compile-time error accounts2.add("my savings"); // Not detected at compile time . . . BankAccount account = (BankAccount) accounts2.getFirst(); // Run-time error Generic ArrayList in JDK 1.5 No Casting Needed

ArrayList list = new ArrayList<>(); list.add(5.5); // 5.5 is automatically converted to new Double(5.5) list.add(3.0); // 3.0 is automatically converted to new Double(3.0)

Double doubleObject = list.get(0); // No casting is needed double d = list.get(1); // Automatically converted to double Raw Type and Backward Compatibility

Ø When generics were introduced into Java, several classes were updated to use generics. Ø Raw types refer to using a generic type without specifying a type parameter. For example, List is a raw type, while List is a parameterized type. Ø Using these class as a raw type allowed legacy code to still compile (backwards compatibility). Ø Although using raw types is still possible, they should be avoided. (I guess by now you know why ? ) Raw Type is Unsafe

Ø What is the output of the code below if we call Max.max("Welcome", 23); ?

// Max.java: Find a maximum object public class Max { /** Return the maximum between two objects */ public static Comparable max(Comparable o1, Comparable o2) { if (o1.compareTo(o2) > 0) return o1; else return o2; } } Make it Safe

Ø What would you change to make it safe ?

// Max1.java: Find a maximum object public class Max1 { /** Return the maximum between two objects */ public static > E max(E o1, E o2) { if (o1.compareTo(o2) > 0) return o1; else return o2; } } Generic Classes

Ø The concept of a , such as a stack, can be understood independently of the element type it manipulates.

Ø Generic classes provide a means for describing the concept of a stack (or any other class) in a type-independent manner.

Ø These classes are known as parameterized classes or parameterized types because they accept one or more type parameters.

public class Stack { .... } Generic Methods

Ø Generic method: method with a type variable Ø Can be defined inside ordinary and generic classes Ø All generic method declarations have a type-parameter section (< T > in this example) delimited by angle brackets that precedes the method’s . Ø Cannot replace type variables with primitive types e.g.: cannot use the generic print method to print an array of type int[] Good practice Overloading Generic Methods

Ø A generic method may be overloaded like any other method. Ø 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 nongeneric methods. Ø When the compiler encounters a method call, it searches for the method declaration that best matches the method name and the argument types specified in the call—an error occurs if two or more overloaded methods both could be considered best matches. Common Error Wildcards in Methods That Accept Type Parameters Ø Suppose that you’d like to implement a generic method sum that totals the numbers in a List. Ø You’d begin by inserting the numbers in the collection. Ø The numbers would be autoboxed as objects of the type-wrapper classes— any int would be autoboxed as an object, and any double value would be autoboxed as a Double object. Ø We’d like to be able to total all the numbers in the List regardless of their type. Ø For this reason, we’ll declare the List with the type argument Number, which is the superclass of both Integer and Double. Ø In addition, method sum will receive a parameter of type List and total its elements.

Types inheritance

Ø In the previous example, it’s not valid to have List numberList= new ArrayList<> (); Ø You can not inherited just a part of a type

Object List

Object Number List

Double List List List

True False True Upper Bounded Wildcards

Ø Given that method sum can total the elements of a List of Numbers, you might expect that the method would also work for Lists that contain elements of only one numeric type, such as List. Ø Modified class TotalNumbers to create a List of and pass it to method sum. Ø When we compile the program, the compiler issues the following error message: Ø sum(java.util.List) in TotalNumbersErrors cannot be applied to (java.util.List) Ø Although Number is the superclass of Integer, the compiler doesn’t consider the parameterized type List to be a superclass of List. Upper Bounded Wildcards (Cont’d)

Ø To create a more flexible version of the sum method that can total the elements of any List containing elements of any subclass of Number we use wildcard-type arguments. Ø Wildcards enable you to specify method parameters, return values, variables or fields, and so on, that act as supertypes or subtypes of parameterized types. Ø Imethod sum’s parameter can be declared with the type: List Ø A wildcard-type argument is denoted by a question mark (?), which by itself represents an “unknown type.” Ø In this case, the wildcard extends class Number, which means that the wildcard has an upper bound of Number. Ø Thus, the unknown-type argument must be either Number or a subclass of Number.

Upper Bounded Wildcards(Cont’d) Ø Because the wildcard (?) in the method’s header does not specify a type-parameter name, you cannot use it as a type name throughout the method’s body Ø You could, however, declare method sum as follows: public static double sum(List list) Ø Allows the method to receive an List that contains elements of any Number subclass. Ø You could then use the type parameter T throughout the method body. Ø If the wildcard is specified without an upper bound, then only the methods of type Object can be invoked on values of the wildcard type. Lower Bounded Wildcards Ø We can specify the lower bound of the wildcard, allowing any generic argument type that is the same or a superclass of the lower bound type to

public static MyList getList() { // ... return MyList, MyList, MyList, etc.... }

Ø What will happen if we pass list of type Double ? Ø Double is not the superclass of Integer Unbounded Wildcard Ø Note: You can specify an upper bound for a wildcard, or you can specify a lower bound, but you cannot specify both. Ø The unbounded wildcard type is specified using the wildcard (?), for example, List. This is called a list of unknown type. Ø There are two scenarios where an unbounded wildcard is a useful approach: Ø If you are writing a method that can be implemented using functionality provided in the Object class. Ø When the code is using methods in the generic class that don't depend on the type parameter. For example, List.size or List.clear. Ø In fact, Class is so often used because most of the methods in Class do not depend on T. Summary Ø We have introduced Java Generics ( What and why? ) Ø We have seen how to use and implement generic classes and methods Ø We have studied Generics types Ø We have studied Wildcard in Java and it’s types. Ø Chapter 20 of Java How To Program (11 e). Ø Oracle documentation https://docs.oracle.com/javase/tutorial/java/generics/i ndex. Ø Chapter 18 of Big Java: Early Objects 6th edition by Horstmann Ø Chapter 19 of Introduction to Java Programming, Brief Version, 11th Edition