Посмотреть байт код java

Как посмотреть байт код java

Для просмотра байт-кода Java можно использовать утилиту javap , которая поставляется вместе с JDK . javap позволяет просмотреть байт-код любого класса, даже если он не содержит исходного кода.

Чтобы просмотреть байт-код класса, следует выполнить следующие шаги:

Эта команда выведет байт-код класса MyClass.

Compiled from "MyClass.java" public class MyClass  public MyClass(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."":()V 4: return public void myMethod(); Code: 0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3 // String Hello, World! 5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 8: return > 

Этот вывод показывает байт-код двух методов класса MyClass : конструктора и метода myMethod()

Источник

Основы Java Bytecode

Как и многие базовые вещи, на habr уже были статьи о bytecode (раз, два), основные же отличия данной статьи — в попытке визуализировать, что происходит внутри, и краткий справочник инструкций (может кому пригодится), многие с примерами использования.

В данной статье будут рассмотрены только основы Java Bytecode. Если вы уже знакомы с его основами, статья вряд ли будет вам интересна, так как практически все можно найти в документации.

В данной статье не рассмотрены многие темы (например, фреймы, многие атрибуты), иначе она бы получилась еще больше

Зачем знать что-то о Bytecode

Тема bytecode довольно скучная и в реальной работе среднестатистического программиста практически не используется.

Так почему стоит знать про основы bytecode:

  • Потому что с этим работает Java Machine и хочется понимать, что лежит в основе
  • Потому что многие современные фреймворки что-то тихо делают на уровне bytecode и часто могут что-то там сломать (привет, Lombok)
  • Потому что просто стало скучно 🙂

Как читать .class файл

Для начала вспомним, как создать .class файл. Для этого воспользуемся

Создается .class файл. Формат class файла — бинарный, файл содержит все, что нужно для выполнения программы JVM. При этом действует правило — 1 класс на 1 файл. В случае вложенных классов создаются дополнительные class файлы.

Если открыть любой class файл в hex редакторе, то файл начинается с «магических байт» — CAFEBABE, а дальше следует полезное содержимое файла.

Для того чтобы просмотреть содержимое, можно воспользоваться стандартной утилитой

javap может принимать много параметров. Давайте рассмотрим основные из них.

Смотреть будем на стандартном классе java.lang.Object

Без параметров

Выводится только основная информация по классам, методам и полям (приватные поля и методы не показываются)

Compiled from "Object.java" public class java.lang.Object < public java.lang.Object(); public final native java.lang.ClassgetClass(); public native int hashCode(); public boolean equals(java.lang.Object); protected native java.lang.Object clone() throws java.lang.CloneNotSupportedException; public java.lang.String toString(); public final native void notify(); public final native void notifyAll(); public final native void wait(long) throws java.lang.InterruptedException; public final void wait(long, int) throws java.lang.InterruptedException; public final void wait() throws java.lang.InterruptedException; protected void finalize() throws java.lang.Throwable; static <>; >

-v

Показываются подробную информацию (verbose), такую, как размер стека и аргументов, версии и т.д.

Classfile jar:file Last modified 15.12.2018; size 1497 bytes MD5 checksum 074ebc688a81170b8740f1158648a3c7 Compiled from "Object.java" public class java.lang.Object minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Integer 999999 #2 = String #16 // @ #3 = String #38 // nanosecond timeout value out of range #4 = String #42 // timeout value is negative #5 = Utf8 ()I #6 = Utf8 ()Ljava/lang/Object; #7 = Utf8 ()Ljava/lang/String; #8 = Utf8 ()V #9 = Utf8 (I)Ljava/lang/String; #10 = Utf8 (J)V #11 = Utf8 (JI)V #12 = Utf8 (Ljava/lang/Object;)Z #13 = Utf8 (Ljava/lang/String;)V #14 = Utf8 #15 = Utf8 #16 = Utf8 @ #17 = Utf8 Code #18 = Utf8 Exceptions #19 = Utf8 LineNumberTable #20 = Utf8 Signature #21 = Utf8 SourceFile #22 = Utf8 StackMapTable #23 = Utf8 append #24 = Utf8 clone #25 = Utf8 equals #26 = Utf8 finalize #27 = Utf8 getClass #28 = Utf8 getName #29 = Utf8 hashCode #30 = Utf8 java/lang/Class #31 = Utf8 java/lang/CloneNotSupportedException #32 = Utf8 java/lang/IllegalArgumentException #33 = Utf8 java/lang/Integer #34 = Utf8 java/lang/InterruptedException #35 = Utf8 java/lang/Object #36 = Utf8 java/lang/StringBuilder #37 = Utf8 java/lang/Throwable #38 = Utf8 nanosecond timeout value out of range #39 = Utf8 notify #40 = Utf8 notifyAll #41 = Utf8 registerNatives #42 = Utf8 timeout value is negative #43 = Utf8 toHexString #44 = Utf8 toString #45 = Utf8 wait #46 = Class #30 // java/lang/Class #47 = Class #31 // java/lang/CloneNotSupportedException #48 = Class #32 // java/lang/IllegalArgumentException #49 = Class #33 // java/lang/Integer #50 = Class #34 // java/lang/InterruptedException #51 = Class #35 // java/lang/Object #52 = Class #36 // java/lang/StringBuilder #53 = Class #37 // java/lang/Throwable #54 = Utf8 ()Ljava/lang/Class; #55 = Utf8 ()Ljava/lang/Class<*>; #56 = Utf8 (Ljava/lang/String;)Ljava/lang/StringBuilder; #57 = NameAndType #29:#5 // hashCode:()I #58 = NameAndType #15:#8 // "":()V #59 = NameAndType #41:#8 // registerNatives:()V #60 = NameAndType #45:#10 // wait:(J)V #61 = NameAndType #27:#54 // getClass:()Ljava/lang/Class; #62 = NameAndType #28:#7 // getName:()Ljava/lang/String; #63 = NameAndType #44:#7 // toString:()Ljava/lang/String; #64 = NameAndType #43:#9 // toHexString:(I)Ljava/lang/String; #65 = NameAndType #15:#13 // "":(Ljava/lang/String;)V #66 = NameAndType #23:#56 // append:(Ljava/lang/String;)Ljava/lang/StringBuilder; #67 = Methodref #46.#62 // java/lang/Class.getName:()Ljava/lang/String; #68 = Methodref #48.#65 // java/lang/IllegalArgumentException."":(Ljava/lang/String;)V #69 = Methodref #49.#64 // java/lang/Integer.toHexString:(I)Ljava/lang/String; #70 = Methodref #51.#57 // java/lang/Object.hashCode:()I #71 = Methodref #51.#59 // java/lang/Object.registerNatives:()V #72 = Methodref #51.#60 // java/lang/Object.wait:(J)V #73 = Methodref #51.#61 // java/lang/Object.getClass:()Ljava/lang/Class; #74 = Methodref #52.#58 // java/lang/StringBuilder."":()V #75 = Methodref #52.#63 // java/lang/StringBuilder.toString:()Ljava/lang/String; #76 = Methodref #52.#66 // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; #77 = Utf8 Object.java < public java.lang.Object(); descriptor: ()V flags: ACC_PUBLIC Code: stack=0, locals=1, args_size=1 0: return LineNumberTable: line 37: 0 public final native java.lang.ClassgetClass(); descriptor: ()Ljava/lang/Class; flags: ACC_PUBLIC, ACC_FINAL, ACC_NATIVE Signature: #55 // ()Ljava/lang/Class<*>; public native int hashCode(); descriptor: ()I flags: ACC_PUBLIC, ACC_NATIVE public boolean equals(java.lang.Object); descriptor: (Ljava/lang/Object;)Z flags: ACC_PUBLIC Code: stack=2, locals=2, args_size=2 0: aload_0 1: aload_1 2: if_acmpne 9 5: iconst_1 6: goto 10 9: iconst_0 10: ireturn StackMapTable: number_of_entries = 2 frame_type = 9 /* same */ frame_type = 64 /* same_locals_1_stack_item */ stack = [ int ] LineNumberTable: line 149: 0 protected native java.lang.Object clone() throws java.lang.CloneNotSupportedException; descriptor: ()Ljava/lang/Object; flags: ACC_PROTECTED, ACC_NATIVE Exceptions: throws java.lang.CloneNotSupportedException public java.lang.String toString(); descriptor: ()Ljava/lang/String; flags: ACC_PUBLIC Code: stack=2, locals=1, args_size=1 0: new #52 // class java/lang/StringBuilder 3: dup 4: invokespecial #74 // Method java/lang/StringBuilder."":()V 7: aload_0 8: invokevirtual #73 // Method getClass:()Ljava/lang/Class; 11: invokevirtual #67 // Method java/lang/Class.getName:()Ljava/lang/String; 14: invokevirtual #76 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 17: ldc #2 // String @ 19: invokevirtual #76 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 22: aload_0 23: invokevirtual #70 // Method hashCode:()I 26: invokestatic #69 // Method java/lang/Integer.toHexString:(I)Ljava/lang/String; 29: invokevirtual #76 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 32: invokevirtual #75 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 35: areturn LineNumberTable: line 236: 0 public final native void notify(); descriptor: ()V flags: ACC_PUBLIC, ACC_FINAL, ACC_NATIVE public final native void notifyAll(); descriptor: ()V flags: ACC_PUBLIC, ACC_FINAL, ACC_NATIVE public final native void wait(long) throws java.lang.InterruptedException; descriptor: (J)V flags: ACC_PUBLIC, ACC_FINAL, ACC_NATIVE Exceptions: throws java.lang.InterruptedException public final void wait(long, int) throws java.lang.InterruptedException; descriptor: (JI)V flags: ACC_PUBLIC, ACC_FINAL Code: stack=4, locals=4, args_size=3 0: lload_1 1: lconst_0 2: lcmp 3: ifge 16 6: new #48 // class java/lang/IllegalArgumentException 9: dup 10: ldc #4 // String timeout value is negative 12: invokespecial #68 // Method java/lang/IllegalArgumentException."":(Ljava/lang/String;)V 15: athrow 16: iload_3 17: iflt 26 20: iload_3 21: ldc #1 // int 999999 23: if_icmple 36 26: new #48 // class java/lang/IllegalArgumentException 29: dup 30: ldc #3 // String nanosecond timeout value out of range 32: invokespecial #68 // Method java/lang/IllegalArgumentException."":(Ljava/lang/String;)V 35: athrow 36: iload_3 37: ifle 44 40: lload_1 41: lconst_1 42: ladd 43: lstore_1 44: aload_0 45: lload_1 46: invokevirtual #72 // Method wait:(J)V 49: return StackMapTable: number_of_entries = 4 frame_type = 16 /* same */ frame_type = 9 /* same */ frame_type = 9 /* same */ frame_type = 7 /* same */ LineNumberTable: line 447: 0 line 448: 6 line 451: 16 line 452: 26 line 456: 36 line 457: 40 line 460: 44 line 461: 49 Exceptions: throws java.lang.InterruptedException public final void wait() throws java.lang.InterruptedException; descriptor: ()V flags: ACC_PUBLIC, ACC_FINAL Code: stack=3, locals=1, args_size=1 0: aload_0 1: lconst_0 2: invokevirtual #72 // Method wait:(J)V 5: return LineNumberTable: line 502: 0 line 503: 5 Exceptions: throws java.lang.InterruptedException protected void finalize() throws java.lang.Throwable; descriptor: ()V flags: ACC_PROTECTED Code: stack=0, locals=1, args_size=1 0: return LineNumberTable: line 555: 0 Exceptions: throws java.lang.Throwable static <>; descriptor: ()V flags: ACC_STATIC Code: stack=0, locals=0, args_size=0 0: invokestatic #71 // Method registerNatives:()V 3: return LineNumberTable: line 41: 0 line 42: 3 > SourceFile: "Object.java" 

В IDEA имеет встроенные средства для просмотра:

Просмотр для JavaПросмотр для Kotlin

Что содержит .class файл

u1 , u2 , and u4 — размер полей

cp_info , field_info , method_info , attribute_info — специальные таблицы, о которых рассказывается ниже

  • magic — магическая константа (0xCAFEBABE), мы о ней уже говорили.
  • minor_version, major_version — версия формата .class файла (смотреть ниже)
  • constant_pool_count и constant_pool — длина пула констант и сам пул констант ( Пул констант — таблица для записи различный текстовых констант, имен интерфейсов, классов, полей и другие константы, на которые в дальнейшем будут ссылки в процессе выполнения, раздел Constant pool при выводе javap -v)
  • access_flags — набор флагов (public, abstract, enum и т.д.)
  • this_class — ссылка на пул констант, которая определяет данный класс
  • super_class — ссылка на пул констант, которая определяет родительский класс
  • interfaces_count и interfaces — количество интерфейсов, которые реализуют класс и ссылки на пул констант для этих интерфейсов
  • fields_count и fields — информация по полям
  • methods_count и methods — информация по методам
  • attributes_count и attributes — информация по атрибутам

Версии class файлов

Довольно часто можно увидеть ошибку, если запускать на более ранней версии jvm: Exception in thread «main» java.lang.UnsupportedClassVersionError: . has been compiled by a more recent version of the Java Runtime (class file version 55.0), this version of the Java Runtime only recognizes class file versions up to 52.0 . Здесь 55.0 и 52.0 — версии class файлов.

Чтобы понять, какие версии class файлов какая jvm поддерживает, можно воспользоваться таблицей из документации:

Источник

Читайте также:  Python 3 для web разработки
Оцените статью