Fundamentals 11 min read

Master Java Generics: Understanding T, ?, extends, and super

This article explains Java generics introduced in JDK 5, covering type safety, the benefits of compile‑time checks, the roles of type parameters like T, E, K, V, the use of wildcards ?, extends, and super, and provides practical code examples illustrating their differences and proper usage.

Java Backend Technology
Java Backend Technology
Java Backend Technology
Master Java Generics: Understanding T, ?, extends, and super

Preface

Java generics were introduced in JDK 5 as a new feature that provides a compile‑time type‑safety mechanism, allowing developers to detect illegal types during compilation.

The essence of generics is parameterized types, meaning the data type being operated on is specified as a parameter.

Benefits of Generics

Without generics, developers often use Object references to achieve type “any‑ness”, which requires explicit casts. Cast errors may not be caught by the compiler and only surface at runtime, posing a safety risk.

Generics eliminate the need for explicit casts by checking type safety at compile time and performing all casts automatically and implicitly.

Basic Generic Class Example

public class GlmapperGeneric<T> {
    private T t;
    public void set(T t) { this.t = t; }
    public T get() { return t; }
    public static void main(String[] args) { /* do nothing */ }
    // No type specified
    public void noSpecifyType() {
        GlmapperGeneric glmapperGeneric = new GlmapperGeneric();
        glmapperGeneric.set("test");
        // need explicit cast
        String test = (String) glmapperGeneric.get();
        System.out.println(test);
    }
    // Specified type
    public void specifyType() {
        GlmapperGeneric<String> glmapperGeneric = new GlmapperGeneric<>();
        glmapperGeneric.set("test");
        // no cast needed
        String test = glmapperGeneric.get();
        System.out.println(test);
    }
}

In the specifyType method the explicit cast is omitted, allowing the compiler to verify type safety.

Wildcards in Generics

When defining generic classes, methods, or interfaces we often encounter placeholders such as T, E, K, V. These are merely conventions; any letter could be used, but the common meanings are: ? – an unknown Java type. T (type) – a concrete Java type. K and V – key and value in a map. E (element) – an element type.

Unbounded Wildcard ?

Used when the actual type is irrelevant. For example, a method that counts legs of any subclass of Animal can be declared as:

static int countLegs(List<? extends Animal> animals) {
    int retVal = 0;
    for (Animal animal : animals) {
        retVal += animal.countLegs();
    }
    return retVal;
}

Calling the same method with a List<Dog> works because ? extends Animal accepts any subclass of Animal. A method that expects List<Animal> would reject it.

Upper‑Bounded Wildcard ? extends E

Using extends declares that the parameterized type may be the specified type or any of its subclasses.

This ensures that only compatible subtypes are passed and that the generic’s methods can be used without casting.

Lower‑Bounded Wildcard ? super E

Using super declares that the parameterized type may be the specified type or any of its supertypes up to Object .

Example:

private <T> void test(List<? super T> dst, List<T> src) {
    for (T t : src) {
        dst.add(t);
    }
}

Here the destination list can hold objects of type T or any of its supertypes, allowing safe copying from src to dst.

Difference Between Class<T> and Class<?>

Class<T>

requires a concrete type argument at instantiation, enabling compile‑time checks. Class<?> represents an unknown type and is useful when the exact class is not known, such as in reflection scenarios.

// Reflection example
MultiLimit multiLimit = (MultiLimit) Class.forName("com.glmapper.bridge.boot.generic.MultiLimit").newInstance();

If the reflected class is not MultiLimit, a ClassCastException occurs at runtime. Using Class<?> can avoid the unchecked cast:

Class<?> clazz = Class.forName("com.glmapper.bridge.boot.generic.MultiLimit");

Conclusion

This article collects scattered points about Java generics, including type parameters, wildcards, and their practical differences. It is not exhaustive but serves as a handy reference.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaprogrammingGenericsType SafetyWildcards
Java Backend Technology
Written by

Java Backend Technology

Focus on Java-related technologies: SSM, Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading. Occasionally cover DevOps tools like Jenkins, Nexus, Docker, and ELK. Also share technical insights from time to time, committed to Java full-stack development!

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.