I was doing a code with reflection in Java 8 when I came across a strange behavior - an ArrayIndexOutOfBoundsException
unexpected. Based on this, I've decided to create a minimal, complete, and verifiable example.
First look at this code:
import java.lang.reflect.Constructor;
import java.lang.reflect.Parameter;
public class BuggyReflection {
public class Test {
public Test(Class k) {
}
}
public static void main(String[] args) throws Exception {
for (Constructor<?> ctor : Test.class.getConstructors()) {
for (Parameter p : ctor.getParameters()) {
System.out.println(p.getParameterizedType());
}
}
}
}
Here's the output:
class BuggyReflection
class java.lang.Class
Now, when I change the constructor parameter type from Class
to Class<?>
:
import java.lang.reflect.Constructor;
import java.lang.reflect.Parameter;
public class BuggyReflection {
public class Test {
public Test(Class<?> k) {
}
}
public static void main(String[] args) throws Exception {
for (Constructor<?> ctor : Test.class.getConstructors()) {
for (Parameter p : ctor.getParameters()) {
System.out.println(p.getParameterizedType());
}
}
}
}
Then an unexpected exception occurs:
java.lang.Class<?>
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 1
at java.lang.reflect.Parameter.getParameterizedType(Parameter.java:201)
at BuggyReflection.main(BuggyReflection.java:14)
Am I doing something wrong? I see no point in making this mistake.
Investigating this code a little more:
import java.lang.reflect.Constructor;
import java.util.Arrays;
public class BuggyReflection {
public class Test {
public Test(Class k) {
}
}
public static void main(String[] args) throws Exception {
for (Constructor<?> ctor : Test.class.getConstructors()) {
System.out.println(Arrays.toString(ctor.getGenericParameterTypes()) + ctor.getParameters().length);
}
}
}
Here is the output, demonstrating that for the JVM there are two parameters in the constructor (since this is a non-static inner class):
[class BuggyReflection, class java.lang.Class]2
Now, if I change the Class
to Class<?>
:
import java.lang.reflect.Constructor;
import java.util.Arrays;
public class BuggyReflection {
public class Test {
public Test(Class<?> k) {
}
}
public static void main(String[] args) throws Exception {
for (Constructor<?> ctor : Test.class.getConstructors()) {
System.out.println(Arrays.toString(ctor.getGenericParameterTypes()) + ctor.getParameters().length);
}
}
}
The result is at least incoherent:
[java.lang.Class<?>]2
Here are the java and javac versions I'm using:
C:\projetos>javac -version
javac 1.8.0_25
C:\projetos>javac -fullversion
javac full version "1.8.0_25-b18"
C:\projetos>java -version
java version "1.8.0_40"
Java(TM) SE Runtime Environment (build 1.8.0_40-b25)
Java HotSpot(TM) 64-Bit Server VM (build 25.40-b25, mixed mode)
C:\projetos>java -fullversion
java full version "1.8.0_40-b25"
I'm strongly inclined to believe that this is a bug in Java, but I wonder if I'm actually doing something wrong or if this exception is somehow foreseen (I did not find anything about it in the documentation).