Я вот пишу ява-машину, точнее только начинаю писать, однако вот наткнулся на непонятнео место. в процессе выполнения мидлета мы вызываем статический метод com.sun.midp.midlet.MIDletState.getState(javax.microedition.midlet.MIDlet); — вроде до этого момента все корректно, да и сама возможность вызова метода вполне очевидна — он public. Вот тут моя ява-машина вываливает AbstractMethodError и завершает работу. посмотрел на содержимое этого класса:
public static com.sun.midp.midlet.MIDletState getState(javax.microedition.midlet.MIDlet);
Code:
Stack=2, Locals=1, Args_size=1
0: getstatic #2; //Field mapImpl:Lcom/sun/midp/midlet/MIDletStateMap;
3: aload_0
4: invokevirtual #3; //Method getStateImpl:(Ljavax/microedition/midlet/MIDlet;)Lcom/sun/midp/midlet/MIDletState;
7: areturn
LineNumberTable:
line 45: 0
LocalVariableTable:
Start Length Slot Name Signature
0 8 0 m Ljavax/microedition/midlet/MIDlet;
protected abstract com.sun.midp.midlet.MIDletState getStateImpl(javax.microedition.midlet.MIDlet);
}
и тут мы видим — что? то что метод getState() делает invokevirtual абстрактного метода getStateImpl().... Спрашивается — что я не так понимаю? Метод не нативный, обычный абстрактный метод — его ведь нельзя вызывать. сначала подумал — может где ошибка и должен вызываться метод getState() класса производного от com.sun.midp.midlet.MIDletState, где абстрактный метод getStateImpl() переопределен, но тогда почему метод getState() имеет public-доступ?
Нет ни одной ява-машины для кпк с поддержкой Bluetooth, 3D, функций Windows mobile 5.0 и вообще много чего.
Но я не совсем понял ответ на мой вопрос — по моему я ясно выразился и сказал что вызывается именно статический метод этого класса. то есть о наследниках речи не идет
Здравствуйте, Grief, Вы писали:
G>Нет ни одной ява-машины для кпк с поддержкой Bluetooth, 3D, функций Windows mobile 5.0 и вообще много чего.
G>Но я не совсем понял ответ на мой вопрос — по моему я ясно выразился и сказал что вызывается именно статический метод этого класса. то есть о наследниках речи не идет
Давай разбираться. Насколько я понял у тебя сомнения по поводу правильности байткода. Хорошо, какой тогда байткод должен генерится на приведенный java код
abstract class MIDletStateMap {
static MIDletStateMap mapImpl;
public static MIDletState getState(MIDlet midlet) {
return mapImpl.getStateImpl(midlet);
}
protected abstract MIDletState getStateImpl(MIDlet midlet);
}
D>D>abstract class MIDletStateMap {
D> static MIDletStateMap mapImpl;
D> public static MIDletState getState(MIDlet midlet) {
D> return mapImpl.getStateImpl(midlet);
D> }
D> protected abstract MIDletState getStateImpl(MIDlet midlet);
D>}
D>
{
public static com.sun.midp.midlet.MIDletState getState(javax.microedition.midlet.MIDlet);
Code:
Stack=2, Locals=1, Args_size=1
0: getstatic #2; //Field mapImpl:Lcom/sun/midp/midlet/MIDletStateMap;
3: aload_0
4: invokevirtual #3; //Method getStateImpl
Ljavax/microedition/midlet/MIDlet
Lcom/sun/midp/midlet/MIDletState;
7: areturn
LineNumberTable:
line 45: 0
LocalVariableTable:
Start Length Slot Name Signature
0 8 0 m Ljavax/microedition/midlet/MIDlet;
protected abstract com.sun.midp.midlet.MIDletState getStateImpl(javax.microedition.midlet.MIDlet);
}
Я и не против, чтобы такой код генерировался. Начну издалека, надеюсь вы мне это простите. И не буду приводить полный байткод, чтобы место не тратить.
Итак, класс
javax.microedition.lcdui.Display имеет метод
getDisplay. Смотрим егобайт код
public static javax.microedition.lcdui.Display getDisplay(javax.microedition.midlet.MIDlet);
Code:
Stack=3, Locals=5, Args_size=1
0: getstatic #22; //Field LCDUILock:Ljava/lang/Object;
3: dup
4: astore_3
5: monitorenter
6: aload_0
7: invokestatic #23; //Method com/sun/midp/midlet/MIDletStateMap.getState:(Ljavax/microedition/midlet/MIDlet;)Lcom/sun/midp/midlet/MIDletState;
Обращаем внимание на инструкцию под номером семь. видим вызов статического метода
getState из класса
com.sun.midp.midlet.MIDletStateMap
Смотрим байт-код этого метода:
public static com.sun.midp.midlet.MIDletState getState(javax.microedition.midlet.MIDlet);
Code:
Stack=2, Locals=1, Args_size=1
0: getstatic #2; //Field mapImpl:Lcom/sun/midp/midlet/MIDletStateMap;
3: aload_0
4: invokevirtual #3; //Method getStateImpl:(Ljavax/microedition/midlet/MIDlet;)Lcom/sun/midp/midlet/MIDletState;
7: areturn
LineNumberTable:
line 45: 0
LocalVariableTable:
Start Length Slot Name Signature
0 8 0 m Ljavax/microedition/midlet/MIDlet;
обращаем внимание на инструкцию номер четыре и видим вызов абстрактного метода этого же класса.
Естесственно я абсолютно уверен в правильности байт-кода явы машины, поэтому очевидно, что я упускаю какую-то деталь. Объясните пожалуйста, где здесь вообще присутствует намек на переопределенный абстрактный метод? Да кажется даже если метод переопределен — разве байткод не будет вызывать кодом invokevirtual именно переопределенный метод, а не абстрактный?
Извините, если вопрос кажется глупым, но я проштудировал спецификацию Java Virtual Machine Specification на предмет вызова методов и все равно не могу понять в чем у меня ошибка.
ну, да, конечно, я дурак. проглядел:
Let C be the class of objectref. The actual method to be invoked is selected by the following lookup procedure:
* If C contains a declaration for an instance method with the same name and descriptor as the resolved method, and the resolved method is accessible from C, then this is the method to be invoked, and the lookup procedure terminates.
* Otherwise, if C has a superclass, this same lookup procedure is performed recursively using the direct superclass of C ; the method to be invoked is the result of the recursive invocation of this lookup procedure.
* Otherwise, an AbstractMethodError is raised.
Здравствуйте, Grief, Вы писали:
G>Нет ни одной ява-машины для кпк с поддержкой Bluetooth, 3D, функций Windows mobile 5.0 и вообще много чего.
А есть сайт проекта? Можно узнать на какой стадии находишься? За основу взял
https://phoneme.dev.java.net?
Дело хорошее, но очень трудоёмкое. Как бы не получилась ещё одна KVM со своими эксклюзивными багами.