...
Code Block |
---|
class Foo<T extends Number> { <S extends T> Foo() {} } |
Capture Conversion Idiom
Overloaded Methods
...
Use Case 2: Find generic constructors whose type parameters extend the enclosing class's own type parameters.
Capture Conversion Idiom
Java 5 introduced wildcards as a variance mechanism for generics. Safety is achieved by restricting accesses to fields and methods based on the position of the type parameter. The unbounded wildcard <?> represents any type and can be used to provide a simple form of bivariance. In practice, this means that List<?> is a supertype of List<T> for any T.
The unbounded wildcard is frequently used as part of the capture conversion idiom. In the code below, the signature of reverse is prefered over rev as it doesn't expose implementation information to the caller. The argument List<?> is passed to rev, which takes a List<T>. However, allowing such a subtype relation would be unsafe. Java provides capture conversion as a solution: the unknown type <?> is captured in a type variable and T is infered to be that type variable within the method rev.
Code Block |
---|
public static void reverse(List<?> list) { rev(list); }
private static <T> void rev(List<T> list) {
List<T> tmp = new ArrayList<T>(list);
for (int i = 0; i < list.size(); i++) {
list.set(i, tmp.get(list.size() - i - 1));
}
}
|
Use Case 3: Find occurrences of the capture conversion idiom.
Overloaded Methods
Overloading methods allows programmers to declare methods with the same name but with different signatures.
For example, one could write an add method that takes a different number of parameters:
Code Block |
---|
public void add(T a) { ... }
public void add(T a, T b) { ... }
public void add(T a, T b, T c) { ... }
|
Often this pattern can be rewritten by using the varargs feature if the overloaded methods' parameters share a single type:
Code Block |
---|
public void add(T a, T ... args) { ... }
|
Related to this use case, recent work has investigated overloading in Java and found that a quarter of overloaded methods are simulating default arguments.
Use Case 4: Find overloaded methods with multiple parameters that share a single type.
Covariant Arrays
In Java and C#, array subtyping is covariant, meaning that type B[] is considered a subtype of A[] whenever B is a subtype of A. However, this relation can cause runtime exceptions. Consider the following Java code where Banana and Apple are subtypes of Fruit:
Code Block |
---|
Banana[] bananas = new Banana[5];
Fruit[] fruit = bananas;
fruits[0] = new Apple(); // ArrayStore Exception
peelBanana(bananas[0]); // Apple???
|
The assignment to the first element of the variable fruit on line 3 will cause an ArrayStore exception. Although statically, the variable fruit has type Fruit[], its runtime type is Banana[] and thus we cannot use it to store an Apple.
Use Case 5: Find occurences of covariant array uses in assignment, method calls, constructor instantiations and return statements.
Evaluation
| Final Array & Anonymous Class | Generic Constructors | Capture Conversion Idiom | Overloaded Methods | Covariant Arrays |
---|---|---|---|---|---|
JTL |
|
| X |
|
|
BBQ | X | X | X | ? |
|
SOUL |
|
|
|
|
|
JQuery | X | X | X | ? | X |
.QL |
|
|
|
|
|
Jackpot |
|
|
|
|
|
PMD |
|
|
|
|
|
...