【问题标题】:java8 generic<T> return type for varargs method broken?varargs 方法的 java8 generic<T> 返回类型损坏?
【发布时间】:2018-07-23 13:16:31
【问题描述】:

我从 Java6 切换到 Java8 后遇到问题。

突然一个

java.lang.ClassCastException:java.base/java.lang.Integer 无法转换为 java.base/[Ljava.lang.Object;

被抛出。

似乎泛型类型无法匹配到 java.lang.reflect.Method.invoke(Object obj, Object... args) 的 varargs 参数。

由于代码是编译干净的并且只会在运行时失败,这对我来说看起来真的很可怕。 顺便说一句,如果源/目标定义为,即使使用java8编译和执行也会成功

我准备了一个 JUnit 小例子来更好地理解:

public class GenericVarArgTest {
private static InnerClass myInnerClass;

@Test
public void testMethodInvocation()
        throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {

    doSomething();

    System.out.println("Done .. all fine");
}

private void doSomething() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
    myInnerClass = this.new InnerClass();
    Method[] methods = myInnerClass.getClass().getMethods();
    for (Method aktMethod : methods) {
        if (aktMethod.getName().equals("printInteger")) {

            // this will always be okay
            // Integer myParam = getSomething();
            // aktMethod.invoke(myInnerClass, myParam);

            // this is just ok, for source / target level <= 1.7 
            aktMethod.invoke(myInnerClass, getSomething());
        }
    }
}

public static <T> T getSomething() {

    final T result = (T) Integer.valueOf(1);

    System.out.println("getSomething will return <T> : " + result);
    return result;
}

public class InnerClass {

    public String printInteger(final Integer aInteger) {
        final String result = "Integer: " + aInteger;
        System.out.println("Will return : " + result);
        return result;
    }
}

我已经使用这个 pom 用 maven 设置了这个小测试:

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>de.test.java</groupId>
<artifactId>compiler-test</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>compiler test</name>
<description>Test the different compiler results    </description>

<properties>
    <java.version>1.8</java.version>

    <project.java.source.level>${java.version}</project.java.source.level>
    <project.java.target.level>${java.version}</project.java.target.level>
</properties>


<build>
    <plugins>
        <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.3</version>
            <configuration>
                <source>${project.java.source.level}</source>
                <target>${project.java.target.level}</target>
            </configuration>
        </plugin>
    </plugins>
</build>


<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
</dependencies>

如果你用

执行这个pom

mvn clean compile test -Djava.version=1.6

一切都很好。 但是用

执行它

mvn clean compile test -Djava.version=1.8

将导致 ClassCastException。

任何提示为什么这种行为已经改变。这是一个错误(还是 1.8 之前的一个错误)? 非常感谢您的任何解释。

【问题讨论】:

  • Java 10 是当前版本。也许如果你更新你的java,问题就会消失。
  • 嗨,即使使用当前最新的 Java 10 版本,我也有这个问题。使用 Java 10 运行但将编译器的源和目标版本设置为 java 1.7 在 Java 10 下仍然有效。不幸的是,我们的代码将在 Java8 环境中运行,我无法更改源和目​​标版本:-(

标签: generics javacompiler


【解决方案1】:

我还没有得出真正的根本原因。但是为了给您提供一些帮助,并非所有 jdk8 版本都存在这种行为。我用 jdk 8u60 测试了代码,它运行良好(没有抛出ClassCastException)。但是,在 jdk 8u144jdk 8u181(在撰写此答案时可用的最新版本)上对其进行测试,得到了 ClassCastException。因此,与此同时,要绕过这个问题,您可以考虑降级到较早的 jdk8 版本,该版本不会描述错误行为。

【讨论】:

  • 您好,请耐心解答。不幸的是,我无法控制我的代码运行的运行时 Java 版本,但有趣的是早期的 Java 8 运行时没有显示此异常。我试图找出这是否是 java 中的一种错误,或者我是否可以找到有关此行为的任何发行说明。因为这个异常发生在(最新的)Java 8、Java 9 和 Java 10 中,我担心它是一个特性而不是错误 :-( 任何进一步的想法/提示都非常欢迎这个主题。
猜你喜欢
  • 2018-10-19
  • 2012-09-23
  • 2020-05-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多