CS F213 Objected Oriented Programming Labsheet 11
Java - Generics
Java Generic methods and generic classes enable programmers to specify, with a single method declaration, a set of related methods, or with a single class declaration, a set of related types, respectively.
Generics also provide compile-time type safety that allows programmers to catch invalid types at compile time.
Using Java Generic concept, we might write a generic method for sorting an array of objects, then invoke the generic method with Integer arrays, Double arrays, String arrays and so on, to sort the array elements.
Types of Java Generics
Generic Classes
A generic class declaration looks like a non-generic class declaration, except that the class name is followed by a type parameter section.
As with generic methods, the type parameter section of a generic class can have one or more type parameters separated by commas. These classes are known as parameterized classes or parameterized types because they accept one or more parameters.
Example
Output
Generic Methods: You can write a single generic method declaration that can be called with arguments of different types. Based on the types of the arguments passed to the generic method, the compiler handles each method call appropriately.
Rules to Define Generic Methods
All generic method declarations have a type parameter section delimited by angle brackets (< and >) that precedes the method's return type ( < E >).
Each type parameter section contains one or more type parameters separated by commas. A type parameter, also known as a type variable, is an identifier that specifies a generic type name.
The type parameters can be used to declare the return type and act as placeholders for the types of the arguments passed to the generic method, which are known as actual type arguments.
A generic method's body is declared like that of any other method. Note that type parameters can represent only reference types, not primitive types (like int, double and char)
Example
Output
Bounded Type Parameters
There may be times when you'll want to restrict the kinds of types that are allowed to be passed to a type parameter. For example, a method that operates on numbers might only want to accept instances of Number or its subclasses. This is what bounded type parameters are for.
To declare a bounded type parameter, list the type parameter's name, followed by the extends keyword, followed by its upper bound.
Following example illustrates how extends is used in a general sense to mean either "extends" (as in classes) or "implements" (as in interfaces). This example is Generic method to return the largest of three Comparable objects
Exaamle
Output
Wildcard in Java Generics
The ? (question mark) symbol represents the wildcard element. It means any type. If we write <? extends Number>, it means any child class of Number, e.g., Integer, Float, and double. Now we can call the method of Number class through any child class object.
We can use a wildcard as a type of a parameter, field, return type, or local variable. However, it is not allowed to use a wildcard as a type argument for a generic method invocation, a generic class instance creation, or a supertype.
Example
Output
Upper Bounded Wildcards
The purpose of upper bounded wildcards is to decrease the restrictions on a variable. It restricts the unknown type to be a specific type or a subtype of that type. It is used by declaring wildcard character ("?") followed by the extends (in case of, class) or implements (in case of, interface) keyword, followed by its upper bound.
Suppose, we want to write the method for the list of Number and its subtypes (like Integer, Double). Using List<? extends Number> is suitable for a list of type Number or any of its subclasses whereas List< Number> works with the list of type Number only. So, List<? extends Number> is less restrictive than List< Number>
Example
Output
Lower Bounded Wildcards
The purpose of lower bounded wildcards is to restrict the unknown type to be a specific type or a supertype of that type. It is used by declaring wildcard character ("?") followed by the super keyword, followed by its lower bound.
Suppose, we want to write the method for the list of Integer and its supertype (like Number, Object). Using List<? super Integer> is suitable for a list of type Integer or any of its superclasses whereas List< Integer> works with the list of type Integer only. So, List<? super Integer> is less restrictive than List< Integer>.
Example
Output
Generic Interfaces
In addition to generic classes and methods, you can also have generic interfaces. Generic interfaces are specified just like generic classes. Here is an example. It creates an interface called MinMax that declares the methods min( ) and max( ), which are expected to return the minimum and maximum value of some set of objects.
Example
Output
The generic interface offers two benefits. First, it can be implemented for different types of data. Second, it allows you to put constraints (that is, bounds) on the types of data for which the interface can be implemented. In the MinMax example, only types that implement the Comparable interface can be passed to T.
Generic Class Hierarchies
Generic classes can be part of a class hierarchy in just the same way as a non-generic class. Thus, a generic class can act as a superclass or be a subclass. The key difference between generic and non-generic hierarchies is that in a generic hierarchy, any type arguments needed by a generic superclass must be passed up the hierarchy by all subclasses. This is similar to the way that constructor arguments must be passed up a hierarchy.
Using a Generic Superclass
The type parameter T is specified by Gen2 and is also passed to Gen in the extends clause. This means that whatever type is passed to Gen2 will also be passed to Gen. For example, this declaration
It is perfectly acceptable for a non-generic class to be the superclass of a generic subclass. For example, consider this program:
Run-Time Type Comparisons Within a Generic Hierarchy
Recall the run-time type information operator instanceof
. As explained, instanceof determines if an object is an instance of a class. It returns true if an object is of the specified type or can be cast to the specified type. The instanceof operator can be applied to objects of generic classes.
Casting
You can cast one instance of a generic class into another only if the two are otherwise compatible and their type arguments are the same.
Type Inference with Generics
Beginning with JDK 7, it became possible to shorten the syntax used to create an instance of a generic type. So now,
can be replaced by
Notice that the instance creation portion simply uses <>, which is an empty type argument list. This is referred to as the diamond operator
. It tells the compiler to infer the type arguments needed by the constructor in the new expression. The principal advantage of this type-inference syntax is that it shortens what are sometimes quite long declaration statements.
A generic class cannot extend Throwable. This means that you cannot create generic exception classes.
Exercises
Exercise 1
Write a Java program that implements a generic method in Main class called swapElements
. The Box class should have a single instance variable, value, of type T. The swapElements method should take an array of type T and swap the elements at the specified positions.
Sample Input (in code)
Sample Output
Exercise 2
Write a Java program that includes a generic class called DataProcessor<T extends Comparable<? super T>>
. The DataProcessor class should have the following methods:
findMax
: Accepts a list of elements of type T or its subtypes and returns the maximum element in the list based on their natural ordering.findMin
: Accepts a list of elements of type T or its subtypes and returns the minimum element in the list based on their natural ordering.computeAverage
: Accepts a list of elements of type T, or its subtypes that extend Number, and returns the average value of the elements as a double.
In the main method, create a list of integers and a list of doubles. Use the DataProcessor class to find and print the maximum and minimum values in each list. Also, compute and print the average of the values in each list.
use wildcards and bounded parameters to achieve the subtypes task
Sample Input
Sample Output
Exercise 3
You are tasked with building an Online Shopping System that allows users to manage their shopping carts and make purchases. The system should support adding products to the shopping cart, removing products from the cart, calculating the total price, and printing the items in the cart. Additionally, the system should provide functionality to print receipts for the purchased items.
Requirements:
The system should have a generic interface Product
that represents a product. The Product interface should have the following methods:
getName
(): Returns the name of the product as a string.
getPrice
(): Returns the price of the product as a double.
The system should have a generic class ShoppingCart< T extends Product>
that represents a shopping cart. The ShoppingCart class should have the following methods:
addItem(T item)
: Adds a product to the shopping cart.
removeItem(T item)
: Removes a product from the shopping cart. calculateTotalPrice()
: Calculates and returns the total price of all items in the shopping cart as a double.
printItems(Printer<? super T> printer)
: Prints the items in the shopping cart using the provided Printer object.
The system should have a class ConsolePrinter< T> that implements the Printer interface.
The ConsolePrinter class should have the following method:
print(T item)
: Prints the provided item to the console.
The system should have a class ReceiptPrinter< T extends Product> that implements the Printer interface
. The ReceiptPrinter class should have the following method:
print(T item)
: Prints the name and price of the provided product as a receipt.
The ShoppingCart class should have an internal data structure, such as a list or a map, to store the products.
The ShoppingCart class should enforce the following constraints:
A product cannot be added to the shopping cart if it already exists in the cart. A product cannot be removed from the shopping cart if it does not exist in the cart. The system should have a class Main that serves as an entry point for the application.
The Main class should provide a simple command-line interface to interact with the online shopping system. The user should be able to choose different operations, such as adding a product to the cart, removing a product from the cart, calculating the total price, and printing the items in the cart.
The main class is given below along with the expected output, implement other classes and methods to achieve the given output
Sample Output
Last updated