Master Java Generics: Understanding Type Erasure and Wildcards
This article explains Java generics, covering basic usage, type erasure, wildcard bounds, and various generic declarations in classes, interfaces, methods, and multi‑type scenarios, illustrated with code examples and reflections on why generics improve type safety and reduce casting in real‑world projects.
This section introduces Java generics, aiming to help readers understand generic usage and common interview questions about type erasure.
Simple example: attempting to add an int to a List<String> causes a compile‑time error, demonstrating that generics enforce type safety during code writing.
It is possible to add multiple types to a list by omitting generic parameters, but this loses compile‑time checks.
Generics act as a type contract; after compilation, the JVM sees them as Object types, which is why type erasure occurs.
Example of a generic class and reflection to inspect its type:
public class BaseBean<T> {
T value;
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
}Using reflection, the value field appears as Object, while the getValue method returns the concrete type (e.g., String), showing that the JVM treats generic types as Object.
Another generic structure with extends keyword to constrain type inheritance:
public interface Base<K, V> {
void setKey(K k);
V getValue();
}In real projects, common response fields like errMsg and status can be placed in a generic base class:
public class BaseBean<T> {
public String errMsg;
public T data;
public int status;
}Generics can also be used in abstract classes and interfaces:
// Abstract class generic
public abstract class BaseAdapter<T> {
List<T> DATAS;
}
// Interface generic
public interface Factory<T> {
T create();
}
// Method generic
public static <T> T getData() {
return null;
}Multi‑parameter generics example:
public interface Base<K, V> {
void setKey(K k);
V getValue();
}Generic abstract class/interface extending another generic:
public interface BaseCommon<K extends Common1, V> extends Base<K, V> {}
public abstract class BaseCommon<K extends Common1, V> implements Base<K, V> {
LinkedList<Map<K, V>> DATAS = new LinkedList<>();
@Override
public void addNode(Map<K, V> map) {
DATAS.addLast(map);
}
@Override
public Map<K, V> getNode(int index) {
return DATAS.get(index);
}
}Wildcard usage: <?> can be used when the exact generic type is unknown.
public class BaseBean<T> {
T value;
public T getValue() { return value; }
public void setValue(T value) { this.value = value; }
}
public class Common extends BaseCommon { }Reflection example with wildcard:
public static void main(String[] args) {
BaseBean<Common> commonBaseBean = new BaseBean<>();
BaseBean<?> common1BaseBean = commonBaseBean;
try {
Method setValue = common1BaseBean.getClass().getDeclaredMethod("setValue", Object.class);
setValue.invoke(common1BaseBean, "123");
Object value = common1BaseBean.getValue();
System.out.println("result:" + value);
} catch (Exception e) {
e.printStackTrace();
}
}Wildcard cannot be placed on class, interface, or method declarations; it is only valid on method parameters, e.g.:
public void setClass(Class<?> class) { /* todo */ }Upper‑bounded ( <T extends>) and lower‑bounded ( <T super>) wildcards control generic limits.
In practice, using generics appropriately reduces the need for explicit casts, improves code readability, and helps avoid runtime errors.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
