AbstractMethodError in Java – Java中的AbstractMethodError

最后修改: 2020年 11月 3日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

Sometimes, we may encounter AbstractMethodError at runtime in our application. If we don’t know this error well, it might take a while to determine the cause of the problem.

有时,我们可能会在应用程序的运行时遇到AbstractMethodError。如果我们对这种错误不甚了解,可能需要花点时间来确定问题的原因。

In this tutorial, we’ll take a closer look at AbstractMethodError. We’ll understand what AbstractMethodError is and when it may happen.

在本教程中,我们将仔细研究AbstractMethodError。我们将了解什么是AbstractMethodError以及何时可能发生。

2. Introduction to AbstractMethodError

2.介绍AbstractMethodError

AbstractMethodError is thrown when an application attempts to call an unimplemented abstract method. 

AbstractMethodError在应用程序试图调用一个未实现的抽象方法时被抛出。

We know that if there are unimplemented abstract methods, the compiler will complain first. Therefore, the application won’t get built at all.

我们知道,如果有未实现的抽象方法,编译器会首先抱怨。因此,应用程序根本就不会被构建。

We may ask how we can get this error at runtime?

我们可能会问,我们怎么能在运行时得到这个错误呢?

First, let’s have a look at where AbstractMethodError fits into the Java exception hierarchy:

首先,让我们看看AbstractMethodError在Java异常层次结构中的位置。

java.lang.Object
|_java.lang.Throwable
  |_java.lang.Error
    |_java.lang.LinkageError
      |_java.lang.IncompatibleClassChangeError
        |_java.lang.AbstractMethodError

As the hierarchy above shows, this error is a subclass of IncompatibleClassChangeError. As its parent class’s name implies, AbstractMethodError is usually thrown when incompatibilities exist between compiled classes or JAR files.

如上面的层次结构所示,这个错误是IncompatibleClassChangeError的一个子类。正如其父类的名字所暗示的,AbstractMethodError通常在编译的类或JAR文件之间存在不兼容的情况下被抛出。

Next, let’s understand how this error can happen.

接下来,让我们了解一下这个错误是如何发生的。

3. How This Error May Happen

3.这个错误是如何发生的

When we build an application, usually we’ll import some libraries to make our work easier.

当我们建立一个应用程序时,通常我们会导入一些库来使我们的工作更容易。

Let’s say, in our application, we include a baeldung-queue library. The baeldung-queue library is a high-level specification library, which contains only one interface:

比方说,在我们的应用程序中,我们包括一个baeldung-queue库。baeldung-queue库是一个高级规范库,它只包含一个接口。

public interface BaeldungQueue {
    void enqueue(Object o);
    Object dequeue();
}

Also, to use the BaeldungQueue interface, we import a BaeldungQueue implementation library: good-queue. The good-queue library also has only one class:

另外,为了使用BaeldungQueue接口,我们导入了一个BaeldungQueue实现库。good-queue。这个good-queue库也只有一个类。

public class GoodQueue implements BaeldungQueue {
    @Override
    public void enqueue(Object o) {
       //implementation 
    }

    @Override
    public Object dequeue() {
        //implementation 
    }
}

Now, if both good-queue and baeldung-queue are in the classpath, we may create a BaeldungQueue instance in our application:

现在,如果good-queuebaeldung-queue都在classpath中,我们可以在应用程序中创建一个BaeldungQueue实例。

public class Application {
    BaeldungQueue queue = new GoodQueue();

    public void someMethod(Object element) {
        queue.enqueue(element);
        // ...
        queue.dequeue();
        // ...
    }
}

So far, so good.

到目前为止,一切都很好。

Someday, we’ve learned that baeldung-queue released version 2.0 and that it ships with a new method:

有一天,我们得知baeldung-queue发布了2.0版本,它带有一个新方法。

public interface BaeldungQueue {
    void enqueue(Object o);
    Object dequeue();

    int size();
}

We want to use the new size() method in our application. Therefore, we upgrade the baeldung-queue library from 1.0 to 2.0. However, we forget to check if there’s a new version of the good-queue library that implements the BaeldungQueue interface changes.

我们想在我们的应用程序中使用新的size()方法。因此,我们将baeldung-queue库从1.0升级到2.0。然而,我们忘记了检查是否有新版本的go-queue库实现了BaeldungQueue接口的变化。

Therefore, we have good-queue 1.0 and baeldung-queue 2.0 in the classpath.

因此,我们在classpath中有good-queue 1.0baeldung-queue 2.0

Further, we start using the new method in our application:

此外,我们开始在我们的应用程序中使用这个新方法。

public class Application {
    BaeldungQueue queue = new GoodQueue();

    public void someMethod(Object element) {
        // ...
        int size = queue.size(); //<-- AbstractMethodError will be thrown
        // ...
    }
}

Our code will be compiled without any problem.

我们的代码将被编译,没有任何问题。

However, when the line queue.size() is executed at runtime, an AbstractMethodError will be thrown. This is because the good-queue 1.0 library doesn’t implement the method size() in the BaeldungQueue interface.

然而,当运行时执行queue.size()行时,将抛出AbstractMethodError。这是因为good-queue 1.0库并没有实现BaeldungQueue接口中的size()方法。

4. A Real-World Example

4.一个现实世界的例子

Through the simple BaeldungQueue and GoodQueue scenario, we may get the idea when an application may throw AbstractMethodError. 

通过简单的BaeldungQueueGoodQueue场景,我们可以了解到应用程序何时会抛出AbstractMethodError。

In this section, we’ll see a practical example of the AbstractMethodError.

在本节中,我们将看到一个关于AbstractMethodError的实际例子。

java.sql.Connection is an important interface in the JDBC API. Since version 1.7, several new methods have been added to the Connection interface, such as getSchema().

java.sql.Connection是JDBC API中的一个重要接口。自1.7版本以来,Connection接口增加了几个新的方法,例如getSchema()

The H2 database is a pretty fast open-source SQL database. Since version 1.4.192, it has added the support of the java.sql.Connection.getSchema() method. However, in previous versions, the H2 database hasn’t implemented this method yet.

H2数据库是一个相当快的开源SQL数据库。从1.4.192版本开始,它增加了对java.sql.Connection.getSchema()方法的支持。然而,在以前的版本中,H2数据库还没有实现这个方法。

Next, we’ll call the java.sql.Connection.getSchema() method from a Java 8 application on an older H2 database version 1.4.191. Let’s see what will happen.

接下来,我们将在较早的H2数据库版本1.4.191上从Java 8应用程序调用java.sql.Connection.getSchema()方法。让我们看看会发生什么。

Let’s create a unit-test class to verify if calling the Connection.getSchema() method will throw AbstractMethodError:

让我们创建一个单元测试类来验证调用Connection.getSchema()方法是否会引发AbstractMethodError

class AbstractMethodErrorUnitTest {
    private static final String url = "jdbc:h2:mem:A-DATABASE;INIT=CREATE SCHEMA IF NOT EXISTS myschema";
    private static final String username = "sa";

    @Test
    void givenOldH2Database_whenCallgetSchemaMethod_thenThrowAbstractMethodError() throws SQLException {
        Connection conn = DriverManager.getConnection(url, username, "");
        assertNotNull(conn);
        Assertions.assertThrows(AbstractMethodError.class, () -> conn.getSchema());
    }
}

If we run the test, it’ll pass, confirming that the call to getSchema() throws AbstractMethodError.

如果我们运行测试,它将通过,确认对getSchema()的调用抛出了AbstractMethodError

5. Conclusion

5.总结

Sometimes we may see AbstractMethodError at runtime. In this article, we’ve discussed when the error occurs through examples.

有时我们会在运行时看到AbstractMethodError。在这篇文章中,我们通过实例讨论了该错误何时发生。

When we upgrade one library of our application, it’s always a good practice to check if other dependencies are using the library and consider updating the related dependencies.

当我们升级我们应用程序的一个库时,检查其他依赖是否使用该库并考虑更新相关的依赖总是一个好的做法。

On the other hand, once we face AbstractMethodError, with a good understanding of this error, we may solve the problem quickly.

另一方面,一旦我们面对AbstractMethodError,只要很好地理解这个错误,我们就可能很快解决问题。

As always, the full source code of the article is available over on GitHub.

一如既往,该文章的完整源代码可在GitHub上获得