1. Общ преглед
Понякога може да срещнем AbstractMethodError по време на изпълнение в нашето приложение. Ако не познаваме добре тази грешка, може да отнеме известно време, за да установим причината за проблема.
В този урок ще разгледаме по-отблизо AbstractMethodError . Ще разберем какво е AbstractMethodError и кога може да се случи.
2. Въведение в AbstractMethodError
AbstractMethodError се изхвърля, когато приложението се опитва да извика неприложен абстрактен метод.
Знаем, че ако има неприложени абстрактни методи, компилаторът първо ще се оплаче. Следователно приложението изобщо няма да се изгради.
Може да попитаме как можем да получим тази грешка по време на изпълнение?
Първо, нека да разгледаме къде AbstractMethodError се вписва в йерархията на Java изключения:
java.lang.Object |_java.lang.Throwable |_java.lang.Error |_java.lang.LinkageError |_java.lang.IncompatibleClassChangeError |_java.lang.AbstractMethodError
Както показва йерархията по-горе, тази грешка е подклас на IncompatibleClassChangeError . Както подсказва името на неговия родителски клас, AbstractMethodError обикновено се изхвърля, когато съществуват несъвместимости между компилирани класове или JAR файлове.
След това нека разберем как може да се случи тази грешка.
3. Как може да се случи тази грешка
Когато изграждаме приложение, обикновено импортираме някои библиотеки, за да улесним работата си.
Да кажем, че в нашето приложение ние включваме библиотека за опашка baeldung . В baeldung-опашка библиотека е библиотеката спецификация на високо ниво, която съдържа само един интерфейс:
public interface BaeldungQueue { void enqueue(Object o); Object dequeue(); }
Също така, за да използваме интерфейса BaeldungQueue , импортираме библиотека за внедряване на BaeldungQueue : добра опашка . Най- добро съотношение качество-опашка библиотеката също има само един клас:
public class GoodQueue implements BaeldungQueue { @Override public void enqueue(Object o) { //implementation } @Override public Object dequeue() { //implementation } }
Сега, ако и двете добре опашка и baeldung-опашка са в CLASSPATH, ние може да създаде BaeldungQueue например в нашата молба:
public class Application { BaeldungQueue queue = new GoodQueue(); public void someMethod(Object element) { queue.enqueue(element); // ... queue.dequeue(); // ... } }
Дотук добре.
Някой ден научихме, че опашката baeldung пусна версия 2.0 и че се доставя с нов метод:
public interface BaeldungQueue { void enqueue(Object o); Object dequeue(); int size(); }
Искаме да използваме метода new size () в нашето приложение. Следователно надграждаме библиотеката baeldung-queue от 1.0 на 2.0 . Забравяме обаче да проверим дали има нова версия на библиотеката с добри опашки, която реализира промените в интерфейса на BaeldungQueue .
Следователно имаме добра опашка 1.0 и опашка baeldung 2.0 в пътя на класа.
Освен това започваме да използваме новия метод в нашето приложение:
public class Application { BaeldungQueue queue = new GoodQueue(); public void someMethod(Object element) { // ... int size = queue.size(); //<-- AbstractMethodError will be thrown // ... } }
Нашият код ще бъде съставен без проблем.
Въпреки това, когато редът queue.size () се изпълни по време на изпълнение, ще бъде хвърлен AbstractMethodError . Това е така, защото библиотеката за добра опашка 1.0 не реализира размера на метода () в интерфейса BaeldungQueue .
4. Пример от реалния свят
Чрез опростения сценарий BaeldungQueue и GoodQueue можем да разберем кога дадено приложение може да хвърли AbstractMethodError.
В този раздел ще видим практически пример за AbstractMethodError .
java.sql.Connection е важен интерфейс в JDBC API. От версия 1.7 към интерфейса за свързване са добавени няколко нови метода , като getSchema ().
Базата данни H2 е доста бърза SQL база данни с отворен код. От версия 1.4.192 той добави поддръжката на метода java.sql.Connection.getSchema () . В предишни версии обаче базата данни H2 все още не е внедрила този метод.
След това ще извикаме метода java.sql.Connection.getSchema () от приложение Java 8 на по-стара версия на базата данни H2 1.4.191 . Да видим какво ще стане.
Нека създадем клас на единичен тест, за да проверим дали извикването на метода 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()); } }
Ако стартираме теста, той ще премине, потвърждавайки, че извикването към getSchema () изхвърля AbstractMethodError .
5. Заключение
Понякога може да видим AbstractMethodError по време на изпълнение. В тази статия обсъдихме кога възниква грешката чрез примери.
Когато надграждаме една библиотека на нашето приложение, винаги е добра практика да проверите дали други зависимости използват библиотеката и да помислите за актуализиране на свързаните зависимости.
От друга страна, след като се сблъскаме с AbstractMethodError , с добро разбиране на тази грешка, можем бързо да разрешим проблема.
Както винаги, пълният изходен код на статията е достъпен в GitHub.