What do those letters in Java generics mean? (E, T, K, V, S)
Detailed explanation of generic classes, generic interfaces, and generic methods!
When defining a class, interface, or method, you can use type parameters (Type Parameters) to represent unknown types, making your code more general and flexible. Examples of classes, interfaces, and methods are given below:
1. Use type parameters in the class:
public class Box<T> {
private T value;
public Box(T value) {
this.value = value;
}
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
}
In this example, Box
the class uses a type parameter T
to represent the unknown type, and the concrete type can be specified when the object is created. For example, a Box
object can be created to store values of integer type:
Box<Integer> integerBox = new Box<>(10);
Integer value = integerBox.getValue(); // 获取整数值
It is also possible to create a Box
object to store values of type string:
Box<String> stringBox = new Box<>("Hello");
String value = stringBox.getValue(); // 获取字符串值
2. Use type parameters in the interface:
public interface List<T> {
void add(T element);
T get(int index);
}
In this example, List
the interface uses type parameters T
to represent unknown types, and concrete types can be specified when implementing the interface. For example, a list of integers can be implemented:
public class IntegerList implements List<Integer> {
private List<Integer> elements = new ArrayList<>();
@Override
public void add(Integer element) {
elements.add(element);
}
@Override
public Integer get(int index) {
return elements.get(index);
}
}
A list of strings can also be implemented:
public class StringList implements List<String> {
private List<String> elements = new ArrayList<>();
@Override
public void add(String element) {
elements.add(element);
}
@Override
public String get(int index) {
return elements.get(index);
}
}
3. Use the type parameter in the method:
public <T> T findMax(T[] array) {
if (array == null || array.length == 0) {
return null;
}
T max = array[0];
for (int i = 1; i < array.length; i++) {
if (array[i].compareTo(max) > 0) {
max = array[i];
}
}
return max;
}
In this example, findMax
the method uses type parameters T
to represent unknown types, and specific type parameters can be passed in when calling the method. For example, this method can be called to find the largest value in an array of integers:
Integer[] numbers = {
1, 5, 3, 9, 2};
Integer max = findMax(numbers); // 获取整数数组中的最大值
This method can also be called to find the largest value in an array of strings:
String[] strings = {
"apple", "banana", "cherry", "date"};
String max = findMax(strings); // 获取字符串数组中的最大值
By using type parameters, classes, interfaces, and methods can represent unknown types at definition time, making code more general and flexible to accommodate different types of data. This is widely used in the framework, here are a few practical examples:
practical example
1. Generics in the Java collection framework:
Many interfaces and classes in the Java collection framework use generics to represent the types of elements in the collection, for example, , ArrayList
, LinkedList
and HashMap
so on. By using generics, these collection classes can support different types of elements at runtime and provide type safety checks at compile time, thus avoiding the possibility of type conversion errors at runtime.
ArrayList<Integer> numbers = new ArrayList<Integer>(); // 创建一个整数列表
numbers.add(1);
numbers.add(2);
numbers.add(3);
int firstNumber = numbers.get(0); // 获取列表中的第一个整数
ArrayList<String> names = new ArrayList<String>(); // 创建一个字符串列表
names.add("Alice");
names.add("Bob");
names.add("Charlie");
String firstName = names.get(0); // 获取列表中的第一个字符串
2. Generics in the Spring Framework:
The Spring Framework is a powerful framework for building Java applications in which generics are used extensively to achieve flexible and extensible functionality. For example, in Spring, generics can be used in scenarios such as dependency injection, data access, and transaction management.
public interface CrudRepository<T, ID extends Serializable> {
T save(T entity); // 保存实体
T findById(ID id); // 根据ID查询实体
void delete(T entity); // 删除实体
// ...
}
In this example, CrudRepository
the interface uses two generic parameters T
and ID
, representing entity type and ID type respectively. By using generics, CrudRepository
specific entity types and ID types can be specified when implementing the interface, thereby realizing support for different entity and ID types.
public class UserRepositoryImpl implements CrudRepository<User, Long> {
// 实现User实体的数据访问操作
// ...
}
In this example, UserRepositoryImpl
the class implements CrudRepository
the interface, and specifies the entity type as User
, and the ID type as Long
, thus realizing User
the data access operation on the entity.
By using generics, general, flexible and extensible functions can be implemented in the framework, thereby improving code reusability and maintainability.
3. Generics in the custom framework:
In a custom framework or library, generics can also be used to achieve general and flexible functions. For example, suppose we are building a general data access layer framework that can support data access operations of different entity types through generics.
public interface CrudRepository<T, ID> {
T save(T entity); // 保存实体
T findById(ID id); // 根据ID查询实体
void delete(T entity); // 删除实体
// ...
}
In this example, we define a generic CrudRepository
interface, where the generic parameter T
represents the entity type and ID
represents the ID type. By using generics, we can CrudRepository
specify specific entity types and ID types when implementing the interface, thereby realizing data access operations on different entities and ID types.
public class UserRepositoryImpl implements CrudRepository<User, Long> {
// 实现User实体的数据访问操作
// ...
}
In this example, UserRepositoryImpl
the class implements CrudRepository
the interface, and specifies the entity type as User
, and the ID type as Long
, thus realizing User
the data access operation on the entity.
By using generics in a custom framework, common functions can be realized, and users can flexibly specify different types of parameters when using the framework, so as to meet different business needs. Such a design can improve the reusability and flexibility of the framework, while avoiding the possibility of type conversion errors and runtime exceptions.
4. Generics in methods:
Using generics in a method can make the method more general and can handle multiple types of input parameters and return values. For example, many methods in the collections framework in Java use generics.
public class CollectionUtils {
public static <T> T getFirstElement(List<T> list) {
if (list != null && !list.isEmpty()) {
return list.get(0);
}
return null;
}
}
In this example, we define a static method getFirstElement
that takes a generic parameter of type List<T>
, and returns type of T
. This means that this method can handle any type List
, such as List<Integer>
, List<String>
etc.
A method using generics can perform type inference based on the actual parameter type when calling, thereby avoiding type conversion errors, and can provide better type safety and code reuse.
In the Spring framework, generics are also widely used to achieve common functions. For example, in Spring's JdbcTemplate class, generics are used to support different types of database operations, thereby reducing repetitive code and improving flexibility.
public class JdbcTemplate {
public <T> T queryForObject(String sql, RowMapper<T> rowMapper) {
// 执行SQL查询,并将结果映射到实体对象
// ...
}
// ...
}
In this example, queryForObject
the method uses a generic parameter T
to indicate the entity type of the query result mapping, and receives a RowMapper<T>
parameter for the result mapping. In this way, query operations on different RowMapper
entity types can be realized by passing in different implementation classes, thus providing better flexibility and versatility.
Summarize:
In Java, generics are a powerful feature that can be used in classes, interfaces, methods, etc. to achieve general, flexible, and type-safe functions. It is also widely used in the framework, which can provide common functions, reduce duplication of code, improve flexibility and type safety, thereby improving code quality and development efficiency.