1 of 12

Generic Types

CS 240: Advanced Software Construction

2 of 12

Generics Overview

  • Generics allow you to specify one or more placeholder (generic) types when creating a class or interface whose actual type is determined when an instance is created
  • Generic types can be used as types for instance variables, method parameters and return values
  • Generics make classes more reusable than they would otherwise be
  • We won’t cover generics in detail, but you need a basic understanding to understand Lambda expressions

3 of 12

Generic Class Example

public class Pair<T, U> {

private T value1;

private U value2;

public Pair(T value1, U value2) {

this.value1 = value1;

this.value2 = value2;

}

public T getValue1() {

return value1;

}

public void setValue1(T value1) {

this.value1 = value1;

}

public U getValue2() {

return value2;

}

public void setValue2(U value2) {

this.value2 = value2;

}

}

4 of 12

Instantiating a Generic Class

Pair<String, Integer> pair1 = new Pair<String, Integer>("Hello", 123);

Pair<String, Integer> pair2 = new Pair<>("Hello", 123);

var pair3 = new Pair<String, Integer>("Hello", 123);

Old way with redundant type declaration

More concise way (diamond syntax)

Even more concise way (var syntax)

5 of 12

6 of 12

Using Generic Classes

Inheritance and Interface Implementation

7 of 12

Inheriting from a Generic Class

Specify types in extends clause:

public class StringPair extends Pair<String, String> {

public StringPair(String value1, String value2) {

super(value1, value2);

}

}

Can pass generic types from a generic subclass:

public class KeyValuePair<V> extends Pair<String, V> {

public KeyValuePair(String value1, V value2) {

super(value1, value2);

}

}

Instantiate without declaring generic types:

StringPair p = new StringPair(“Hello”, “BYU”);

Instantiate by declaring a type for V:

KeyValuePair<Date> pair4 =

new KeyValuePair<>("Hello", new Date());

8 of 12

Using a Generic Interface

public interface Function<T, R> {

R apply(T param);

}

public class Capitalizer implements

Function<String, String> {

@Override

public String apply(String param) {

return param == null ? null :

param.toUpperCase();

}

}

public class StringManipulator {

public String manipulateString(String str,

Function<String, String> manipulationFunction) {

return manipulationFunction.apply(str);

}

}

public static void main(String[] args) {

Function<String, String> cap = new Capitalizer();

var sm = new StringManipulator();

String s = sm.manipulateString(args[0], cap);

}

9 of 12

10 of 12

Generic Type Wildcards

11 of 12

Generic Type Wildcards

  • Wildcards with special syntax can be used to expand the acceptable types.
  • Example:

public class GenericClassExample<T> {

public void method1(List<? super T> param) {};

public void method2(List<? extends T> param) {};

public T method3() { return null;}

}

  • In this example, method1 accepts a List of whatever T is, or of any of T’s super classes.
  • Replacing super with extends results in the method accepting a list of T’s or any of T’s subclasses.

12 of 12