midnite
midnite

Reputation: 5286

What if a native class/method only defined in a newer Java version?

As far as i know, during the compile time of Java, only the class/method signatures are recorded. The actual implementations are binded until the running time, in the JVM.

Let's imagine there is a native Java class called MyClass. And in Java version 1.6:

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

And in Java version 1.7:

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

Our IDE and compiler are 1.7. After the program compiled, when we run it in JRE 1.6 and 1.7, we will have different return values from NativeClass.getVersion();. This is known.

But what will happen if we run NativeClass.somethingMore() on JRE 1.6?

If possible, please give an example in the real Java source, where certain class/method only exist in a newer version.

Upvotes: 0

Views: 914

Answers (3)

Andrew Thompson
Andrew Thompson

Reputation: 168795

But what will happen if we run NativeClass.somethingMore() on JRE 1.6?

A NoSuchMethodError will be thrown.

Thrown if an application tries to call a specified method of a class (either static or instance), and that class no longer has a definition of that method.


What if a class that doesn't exist? There is no NoSuchClassError

See NoClassDefFoundError & ClassNotFoundException.

But don't ask me a) why there are two of them. b) why one is used over the other/what the difference is, or c) why methods also have NoSuchMethodException.

It seems they should all be an Error rather than an Exception.

Upvotes: 2

Stephen C
Stephen C

Reputation: 718678

Andrew Thomson is correct as far as he goes. Here's a more fulsome answer:

The first point is that if you compile code using a Java 1.7 SDK (or IDE), and try to run it on Java 1.6 (or earlier), you may run into a "magic number" error. Basically, unless the "target version" is set to the older version, the compiler will emit bytecode files that the older JVM cannot understand.

Once you have gotten past that:

  • Attempting to call a method that doesn't exist will result in a NoSuchMethodError.

  • Attempting to use (in any way) a class that doesn't exist will result in a ClassDefNotFoundError.

The errors are detected and thrown at the point when the JVM tries to resolve the dependencies between the classes. (This is referred as "linking" in the JLS. It happens some time before the class is "initialized", but the JVM is free to implement loading and linking lazily so it might not happen instantly on application startup.

Both of these are fatal errors. They leave the JVM in a state where the application is unlikely to be able to recover because an indeterminate set of the application's essential classes are not usable.

These are examples of "binary compatibility errors". Other examples include things like missing fields, methods with the wrong signatures, some changes in access modifiers, changes to the inheritance hierarchy, and so on. (There is a whole JLS chapter that deals with the binary compatibility rules; i.e. what you can and can't change in a class without breaking compatibility.)

This is all common sense really. If you attempt to call a method that isn't there or use a class that isn't there, bailing out with a fatal error is the only safe thing to do. There are practical limits to "write once, run anywhere".


If you want a simple example, try running an application that uses String.isEmpty() on a Java 1.5 or earlier JVM. (Or an early release Android phone ...)


You won't get a ClassNotFoundException. That is only thrown when you attempt to load classes using Class.forName(...).

Upvotes: 1

Evgeniy Dorofeev
Evgeniy Dorofeev

Reputation: 135992

This code works well with the latest MySQL JDBC driver - mysql-connector-5.1.22

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

but if I use an older version, eg mysql-connector-5.1.20 I'll get

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

because Connection.getSchema is since 1.7.

If a concrete class is missing, eg. Integer.compare(int, int) is since 1.7 you'll get java.lang.NoSuchMethodError

If a JRE class was missing, e.g. java.util.Scanner is since 1.5 and I used JRE 1.4 I would get java.lang.NoClassDefFoundError

Upvotes: 0

Related Questions