-
Notifications
You must be signed in to change notification settings - Fork 48
Generic
There are three ways to use generics: Generic Class, Generic Interface, Generic Method
Generic type used in the definition of class is called Generic Class, such as: List, Set, Map, etc.
- Generic type parameter can be any letter between A-Z, such as T, E, K, V, etc.
class [class name] <[Generic type parameter: any letter between A-Z]> {
private [Generic type parameter: any letter between A-Z] [variable name];
....
}
// When instantiating a generic class, the specific type of T must be specified
public class Generic<T> {
// The type of the key variable is T, and T is specified externally
private final T key;
// The type of the parameter key of the generic constructor is T, and T is specified externally
public Generic(T key) {
this.key = key;
}
// The return value type of the generic method is T, and T is specified externally
public T getKey() {
return key;
}
}
public static void genericExample() {
// The type of the argument passed in must be the same as the generic type parameter, which is Integer.
Generic<Integer> genericInteger = new Generic<Integer>(123);
// The type of the argument passed in must be the same as the generic type parameter, which is String.
Generic<String> genericString = new Generic<String>("Hello World");
System.out.println("key is " + genericInteger.getKey());
System.out.println("key is " + genericString.getKey());
}
/* Output */
key is 123
key is Hello World
- When using generics, if the generic type parameter is defined, the restriction of generic will take effect. Otherwise, the type of the Generic Method or variable in the Generic Class can be defined as any type.
public static void genericExample2() {
Generic generic1 = new Generic("Hello World");
Generic generic2 = new Generic(123);
Generic generic3 = new Generic(123.45);
Generic generic4 = new Generic(true);
System.out.println("key is " + generic1.getKey());
System.out.println("key is " + generic2.getKey());
System.out.println("key is " + generic3.getKey());
System.out.println("key is " + generic4.getKey());
}
/* Output */
key is Hello World
key is 123
key is 123.45
key is true
- Generic type parameter can only be reference type, not primitive type.
- Cannot use the instanceof operation on a generic class defined by the certain type.
// Error
if (genericInteger instanceof Generic<Integer>) {
}
The definition and usage of Generic Interface and Generic Class are basically the same.
public interface IGeneric<T> {
public T next();
}
/**
* The generic declaration needs to be added to the class if the generic type parameter is not defined,
* which is class FruitGeneric<T> implements IGeneric<T> {.
* If the generic is not declared, such as:class FruitGeneric<T> implements IGeneric<T>,
* compilation error will be thrown:"Unknown class".
*/
class FruitGeneric<T> implements IGeneric<T> {
@Override
public T next() {
return null;
}
}
When the class that implements the Generic Interface defines the generic type parameter, such as String
/**
* Only one Generic Interface IGeneric<T> is created,
* but the generic type parameter T can be defined as different types
* to form different types of Generator interface.
* Note: all the T in IGeneric<T>, such as IGeneric<T>,public T next(); must be replaced with String.
*/
public class FruitGeneric implements IGeneric<String> {
private String[] fruits = new String[]{"Apple", "Banana", "Pear"};
@Override
public String next() {
Random rand = new Random();
return fruits[rand.nextInt(3)];
}
}
- Generic Class: Specify the specific type of generic when instantiating the class.
- Generic Method: Specify the specific type of generic when calling the method.
- The between public and the return type T can be regarded as declaring this method as a Generic Method.
- Only method that declare is Generic Method, otherwise, it is not a Generic Method.
- indicates that the method will use the generic type T, then the generic type T can be used in the method.
- Generic type parameter can be any letter between A-Z, such as T, E, K, V, etc.
- If the generic type parameter in the Generic Method and the Generic Class are the same letter, such as T, these two Ts are different.
public <T> T getKey(Generic<T> generic) {
// return type is T, which is the same as the generic type parameter of Generic<T>
return generic.getKey();
}
// This is a Generic Class as mentioned above
public class Generic<T> {
private final T key;
public Generic(T key) {
this.key = key;
}
/**
* Generic is used in the method, but this is not a Generic Method.
* This is just a normal method, but its return type is T, which the Generic Class has already declared.
* Therefore, the generic type parameter T can still be used in this method.
*/
public T getKey() {
return key;
}
/**
* This method will cause a compilation error "cannot resolve symbol E".
* The generic type parameter E is not declared in the class declaration as well as the method declaration,
* the compiler will not recognize it when E is used as the generic type parameter and return type.
*/
public E setKey1(E key) {
this.key = key;
return this.key;
}
// This is not a Generic Method, just uses the T as the type of the generic parameter.
public void showKeyValue1(T key) {
System.out.println("key value is " + key);
}
// This is not a Generic Method, just uses the Generic<T> as the type of the parameter g.
public void showKeyValue2(Generic<T> g) {
System.out.println("key value is " + g.getKey());
}
// This is not a Generic Method, just uses the Generic<?> as the type of the parameter g.
public void showKeyValue3(Generic<?> g) {
System.out.println("key value is " + g.getKey());
}
/**
* This method will cause a compilation error "cannot resolve symbol E".
* Only the generic type parameter T is declared in the method declaration,
* but E is not declared in the class declaration as well as the method declaration,
* the compiler cannot recognize it when E is used as the generic type parameter.
*/
public <T> T showKeyValue4(Generic<E> g) {
...
}
/**
* This is a Generic Method.
* The <T> between public and the return type T is necessariy,
* which indicates that this is a Generic Method and declares a generic type parameter T.
*
* Note: The generic type parameter T in this Method is different from the generic type
* parameter T in the Generic Class.
* In order to distinguish them more easily, it is better to use different letters.
*
* The number of generic type parameters can also be multiple, such as:
* public <T,K> K showKeyValue6(Generic<T> g) {
* ...
* }
*/
public <T> T showKeyValue5(Generic<T> g) {
System.out.println("key value is " + g.getKey());
T key = g.getKey();
return key;
}
}
- If the static method uses generic, the static method must also be defined as a Generic Method.
public class StaticGeneric<T> {
/**
* If you define a static method using generic, you need to add an additional generic declaration
* to define this method as a generic method
* Static methods cannot use the generic type parameter that has been declared in a Generic Class such as T
* For example: public static void show(T t) { ... }, compilation error will be thrown:
* "StaticGeneric cannot be refrenced from static context"
*/
public static <T> void show(T t) {
...
}
}
public static <T> void printMsg(T... args) {
for(T t : args){
System.out.println("t is " + t);
}
}
printMsg("Hello World", 123, 123.45, false);
/* Output */
t is Hello World
t is 123
t is 123.45
t is false
Generic Type Parameter and Generic Wildcard
When using generic, we can also limit the upper and lower boundaries of the generic formal parameters. For example, the generic formal parameters are only allowed to pass in a certain type of superclass or a certain type of subclass.
The formal parameters passed in must be a subclass of the specified class
public static void showValue(Generic<? extends Number> obj) {
System.out.println("key is " + obj.getKey());
}
public static void main(String[] args) {
Generic<String> generic1 = new Generic<String>("11111");
Generic<Integer> generic2 = new Generic<Integer>(2222);
Generic<Float> generic3 = new Generic<Float>(2.4f);
Generic<Double> generic4 = new Generic<Double>(2.56);
// The compiler will throw an error for this line of code
// because String is not a subclass of Number
// showValue(generic1);
showValue(generic2);
showValue(generic3);
showValue(generic4);
}
The formal parameters passed in must be a subclass of the specified class
// This is a Generic Class as mentioned above
public class Generic<T extends Number> {
private T key;
public Generic(T key) {
this.key = key;
}
public T getKey() {
return key;
}
}
The formal parameters passed in must be a subclass of the specified class
Must be defined on the between public and the return type
/**
* public <T> T showKeyName(Generic<T extends Number> container),
* the compiler will throw an error:"Unexpected bound"
*/
public <T extends Number> T showKey(Generic<T> container) {
System.out.println("container key: " + container.getKey());
T test = container.getKey();
return test;
}
public static void main(String[] args) {
// The compiler will throw an error for this line of code
// because String is not a subclass of Number
// Generic<String> generic1 = new Generic<String>("11111");
}
Java does not support Generic Array. The following code will throw an error
List<String>[] ls = new ArrayList<String>[10];
but the following code can work
List<String>[] ls = new ArrayList[10]
Peer Learning
Codecrunch Contributions
Piazza Contributions
Wiki Contributions
Guides
Setting Up Checkstyle
Setting Up Java
Setting Up MacVim
Setting Up Sunfire
Setting Up Unix For Mac
Setting Up Unix For Windows
Setting Up Vim
Setting up SSH Config
CS2030 Contents
Lecture 1 SummaryCompile-run vs Run-time Summary
Quick Guide To Abstraction
Generics and Variance of Types
Comparable vs Comparator
Summary of completable future
CS2030S Notes
ELI5 Optional.map vs Optional.flatMap
PECS Example Code
Java Collection Framework (Iterator)
Generic
Generic Type Parameter and Generic Wildcard
Calculator
Lambda-Expression
Single Abstract Method (SAM)
Method Reference
Functional Interfaces 2
Simple Usage of Sandbox
Associative-but-not-commutative
Higher Order function
Functional Programming
Calculator With Functor
Eager Evaluation VS Lazy Evaluation
Simple Usage of Lazy Evaluation
Lazy Evaluation for LazyList
Lazy Evaluation for BinaryTree
Stream
Parallel Stream
Optional
Simple Usage of Stream
Asynchronous Programming
Notes on CompletableFuture
Notes on CompletableFuture 2
Simple Usage of CompletableFuture
Mind Map
Exception Handling
Links
CS2030 Java Style Guide
CS2030 Javadoc Specification
JDK 11 Download Link
JDK 11 API Docs
Codecrunch
Piazza Forum