2011-02-10 14 views
11

Pracuję nad własną implementacją maszyny JVM i zapoznałem się z instrukcją checkcast. Pełna dokumentacja to on this page. Jestem ciekawy, ponieważ podczas wyliczania reguł działania rzutowania, jednym z sprawdzanych warunków jest to, czy sprawdzany odnośnik obiektu ma typ interfejsu. Według mojego zrozumienia nie powinno to być możliwe; interfejsów nie można bezpośrednio utworzyć, a każdy obiekt implementujący interfejs ma inny konkretny typ klasy. Czy czegoś brakuje?Zamieszanie instrukcji check bytecode?

Odpowiedz

20

Wydaje się, że nie jesteś jedyną osobą, zna tej definicji tego blogu ma wyjaśnienie: http://mbravenboer.blogspot.com/2008/12/why-jvm-spec-defines-checkcast-for.html

Okazuje się, że jest to rzeczywiście niemożliwe `” przypadek. Powodem, dla którego ten element jest w opisie jest dlatego checkcast rekurencyjnie zdefiniowane dla tablic:

  • Jeśli S klasy reprezentującą typ tablicy SC [], to znaczy szereg elementów typu SC a następnie:
  • ...
  • Jeżeli T jest macierzowych TC [], to znaczy szereg elementów typu TC, a następnie jeden z następujących muszą być spełnione:
    • ...
    • TC i SC są typami odniesienia, a typ SC może b e rzucaj do TC przez rekurencyjne stosowanie tych reguł.

Tak więc, jeśli masz obiekt typu listy [], który jest rzutowany na [], a następnie zasady checkcast powołuje się rekurencyjnie dla typów S = list i T = Kolekcja Kolekcja. Zauważ, że List jest interfejsem, ale obiekt może mieć typ List [] w czasie wykonywania. Jeśli nie zweryfikowałeś tego z opiekunami specyfikacji JVM, ale z tego co widzę, jest to jedyny powód, dla którego istnieje reguła dotycząca typów interfejsów.

+0

Dziękuję bardzo! Właśnie takiej odpowiedzi szukałem. – templatetypedef

+0

+1 Brilliant. :) – biziclop

-2

Jeśli S typu interfejsu, a następnie:

Jeżeli T jest typu klasy, należy T będzie obiektu (§2.4.7).
Jeśli T jest typem interfejsu, to T musi być tym samym interfejsem co S lub superinterfejsem S (§2.13.2).

Wydaje mi się to oczywiste: interfejs można rzutować na interfejs, który został przedłużony. Ten przypadek jest używany na przykład, gdy wywołujesz serializację w DataInputStream: interfejs DataInputStream implementuje Serializable, więc rzutujemy obiekt na Serializable, nawet nie wiedząc, jaka jest klasa zaimplementowana obiektu.

+1

Myślę, że nie rozumiesz pytania. Ponadto [java.io.DataInputStream] (https://docs.oracle.com/javase/8/docs/api/java/io/DataInputStream.html) jest klasą, a nie interfejsem. –