У меня есть класс, который вызывает собственную функцию для получения информации о системе от ее CMOS. Класс имеет статический блок инициализации, который загружает библиотеку, содержащую собственную функцию, и это выглядит примерно так:
package lib.sysid;
public class SysId
{
private static native int getSysIdNative();
private static final String SYS_ID_PATH = "libsysid.so";
static
{
System.load(SYS_ID_PATH);
}
public static int getSysIdFromCMOS()
{
int returnValue = getSysIdNative();
}
}
Согласно моему тестированию, метод хорошо работает в первый раз, когда я использую его, но если я называю метод снова в более позднее время, статический блок инициализации также работает, вызывая UnsatisfiedLinkError:
java.lang.UnsatisfiedLinkError: Native Library libsysid.so already loaded in another classloader
Как я могу избежать статического блока инициализации от выполнения System.load()
метод, если это было уже выполнено?
С другой стороны, есть ли способ для меня попытаться "разгрузить" библиотеку, если это уже загружается прежде, чем звонить System.load()
метод снова?
Править: Странно достаточно, если я окружаю System.load()
звоните с блоком try-catch, я все еще получаю UnsatisfiedLinkError, но на этот раз он прибывает от фактического вызова до getSysIdNative()
. Ошибка, которую я вижу, следующая:
lib.sysid.SysId.getSysIdNative()I
Какого черта то, что "I", который обнаруживается? Я попытался присоединить отладчик к этому коду для наблюдения, где сообщение заполняется, но до сих пор я не был успешен.
Просто предположение, но я думаю, что единственный способ для одной JVM загрузить класс (и выполнить его статические инициализаторы) дважды - это загрузить его разными загрузчиками классов. Таким образом, здесь может быть задействован второй загрузчик классов, о котором вы не знаете. Это применимо, если во второй раз действует другой (набор) загрузчиков классов.
В «реальной» операционной системе java -verbose: class
будет выдавать вам сообщения загрузчика для проверки. Я не уверен, как бы вы проверили это во встроенной системе. Вы можете изменить getSysId ()
для печати (?) Или каким-то образом выгрузить ссылку на SysId.class.getClassLoader ()
.
Думаю, @Carl прав. Единственный способ, которым статический инициализатор может запускаться дважды в JVM, - это если класс загружается в нескольких загрузчиках классов.
lib.sysid.SysId.getSysIdNative () I
Что, черт возьми, за то «я», которое появляется?
Это просто. I
основан на внутреннем представлении типов в сигнатурах, который определяется форматом файла класса. В частности, I
означает примитивный тип int
; см. Class.getName () и т. д. Это соответствует типу возвращаемого значения вашего метода.
(Немного сбивает с толку то, что эти имена примитивных типов иногда появляются в пространстве приложения, но они появляются. Другой случай, когда вы можете увидеть их, - это когда вы вызываете toString ()
в классе, который наследует реализацию метода от класса Object
.)