如果仅在较新的Java版本中定义本机类/方法会怎样?

时间:2013-06-11 02:06:59

标签: java version bytecode java-bytecode-asm

据我所知,在Java的编译期间,只记录了类/方法签名。实际的实现在JVM中绑定到运行时间。

让我们假设有一个名为MyClass原生 Java类。在Java 1.6版本中:

public class NativeClass {
    public String getVersion() { return "1.6"; }
}

在Java 1.7版中:

public class NativeClass {
    public String getVersion() { return "1.7"; }
    public String somethingMore() { return "more"; }
}

我们的IDE和编译器是1.7。在编译程序之后,当我们在JRE 1.6和1.7中运行它时,我们将从NativeClass.getVersion();获得不同的返回值。这是众所周知的。

但是如果我们在JRE 1.6上运行NativeClass.somethingMore()会怎样?

如果可能的话,请在真正的Java源代码中举例说明,其中某些类/方法仅存在于较新的版本中。

3 个答案:

答案 0 :(得分:2)

  

但是如果我们在JRE 1.6上运行NativeClass.somethingMore()会发生什么?

将抛出NoSuchMethodError

  

如果应用程序试图调用类的指定方法(静态或实例),并且该类不再具有该方法的定义,则抛出该异常。


  

如果一个课程不存在怎么办?没有NoSuchClassError

NoClassDefFoundError& ClassNotFoundException

但不要问我a)为什么有两个。 b)为什么一个用于另一个/差异是什么,或c)为什么方法也有NoSuchMethodException

它们似乎都应该是Error而不是Exception

答案 1 :(得分:1)

安德鲁汤姆森就他而言是正确的。这是一个更加全面的答案:

第一点是,如果使用Java 1.7 SDK(或IDE)编译代码,并尝试在Java 1.6(或更早版本)上运行代码,则可能会遇到“幻数” “错误。基本上,除非将“目标版本”设置为旧版本,否则编译器将发出旧JVM无法理解的字节码文件。

一旦你完成了这个:

  • 尝试调用不存在的方法将导致NoSuchMethodError

  • 尝试使用(以任何方式)不存在的类将导致ClassDefNotFoundError

当JVM尝试解析类之间的依赖关系时,会检测并抛出错误。 (这在JLS中称为“链接”。它发生在类“初始化”之前的某个时间,但是JVM可以自由地实现加载和链接延迟,因此它可能不会立即在应用程序启动时发生。

这两个都是致命错误。它们使JVM处于应用程序不可能恢复的状态,因为应用程序的基本类的不确定集不可用。

这些是“二进制兼容性错误”的示例。其他示例包括缺少字段,具有错误签名的方法,访问修饰符中的一些更改,继承层次结构的更改等等。 (有一个完整的JLS章节涉及二进制兼容性规则;即在不破坏兼容性的情况下,您可以在一个类中进行更改,也可以不进行更改。)

这真的是常识。如果你试图调用一个不在那里的方法或者使用一个不在那里的类,那么用一个致命的错误拯救是唯一安全的事情。 “一次写入,随处运行”有实际限制。


如果您想要一个简单示例,请尝试在Java 1.5或更早版本的JVM上运行使用String.isEmpty()的应用程序。 (或早期发布Android手机......)


你不会得到ClassNotFoundException。只有在尝试使用Class.forName(...)加载类时才会抛出此内容。

答案 2 :(得分:0)

此代码适用于最新的MySQL JDBC驱动程序 - mysql-connector-5.1.22

Connection conn = DriverManager.getConnection"jdbc:mysql://localhost:3306/test", "root", "root");
conn.getSchema();

但如果我使用旧版本,例如mysql-connector-5.1.20,我会得到

Exception in thread "main" java.lang.AbstractMethodError: com.mysql.jdbc.JDBC4Connection.getSchema()Ljava/lang/String;
    at main.MySQL.main(MySQL.java:21)

因为Connection.getSchema是1.7以来。

如果缺少具体课程,例如。 Integer.compare(int,int)从1.7开始就会得到java.lang.NoSuchMethodError

如果缺少JRE课程,例如java.util.Scanner从1.5开始,我使用的是JRE 1.4,我会得到java.lang.NoClassDefFoundError