Java泛型:通配符适用场景及语法疑问
Great question—let's break this down step by step, since Java generics can feel surprisingly nuanced once you dig past the basics.
1. Why Do We Need Wildcards If Type Parameters Work?
You're right that in some simple cases (like your boundedMethod1 vs boundedMethod2 examples), wildcards and type parameters can seem interchangeable. But they serve different purposes, and wildcards shine in specific scenarios:
When to Use Wildcards
Wildcards are all about flexibility and simplicity when you don't need to track a specific type across multiple parts of the method:
- Read-only collections (
? extends T): Use this when you only need to retrieve elements from a collection (and treat them as typeT). For example, a method that prints allDepartmentobjects (includingDevelopmentandSalessubclasses) doesn't care about the exact subclass type—it just needs to read elements asDepartment. Wildcards make the method signature cleaner without declaring an extra type parameter. - Write-only collections (
? super T): Use this when you only need to add elements of typeT(or its subclasses) to a collection. The classic example isCollections.addAll(), which takes aCollection<? super T>—it doesn't care what the collection's base type is, as long as it can acceptTelements. - Avoiding unnecessary type parameter clutter: If your method doesn't need to reuse the type (e.g., no return type tied to the parameter type, no multiple parameters that need to share the same type), wildcards are more concise than declaring a type parameter.
When to Use Type Parameters Instead
Type parameters are necessary when you need to link types across method parameters, or between parameters and the return type:
- For example, if you want a method that returns the first element of a list and preserves its exact subclass type:
You can't do this with<H extends Department> H getFirstElement(List<H> list) { return list.get(0); // Returns H, not just Department }List<? extends Department>—the return type would have to beDepartment, losing the subclass type information. - Type parameters also let you perform operations that require knowing the exact type (like creating new instances of the type, though you'd need a
Class<H>token for that).
As for Effective Java's note about avoiding wildcards in return types: this is because forcing callers to handle wildcards (like List<? extends Department>) adds unnecessary complexity. Callers would have to deal with restrictions on modifying the list, or cast elements, which defeats the purpose of type safety. Wildcards are better suited for method parameters where the flexibility benefits the caller without extra overhead.
2. Why Can't We Declare Bounded Type Parameters Inside List<>?
The short answer is: Java's generics syntax rules don't allow it. Here's why:
Type variables (like U in your examples) and their bounds (like extends SuperClass) must be declared upfront in the method's type parameter list (the <> before the return type). When you write List<U extends SuperClass>, the compiler has no idea what U is—you haven't declared it as a type variable anywhere.
Let's compare your valid vs invalid examples:
- Valid:
<U extends Building> void boundedListMethod1(List<U> list)
Here,<U extends Building>tells the compiler: "Uis a type variable that extendsBuilding". NowList<U>is valid, becauseUis a known, bounded type. - Invalid:
void notWorkingMethod1(List<U extends SuperClass> list)
The compiler seesUinsideList<>but has no prior declaration of whatUis. There's no place to specify its bound here—bounds can only be set when you first declare the type variable, not when you use it in a generic type likeList.
Even if you added <U> to the method (like <U> void notWorkingMethod1(List<U extends SuperClass> list)), it's still invalid. The extends SuperClass part can't be inside the List<>—it has to be part of the type variable declaration: <U extends SuperClass>.
In short: Type variable bounds are part of the variable's declaration, not its usage.
内容的提问来源于stack exchange,提问作者Harsh Kanakhara

