Восстановите сигнатуру метода по дескриптору, который печатает javap
javap печатает дескриптор каждого метода — принятую в class-файле запись типов параметров и возвращаемого значения, где (I)V означает void f(int). Для класса ниже команда javap -s -p Descriptors должна напечатать для метода pick ровно дескриптор (Ljava/lang/String;[IJ)Ljava/util/List;.
Ограничения:
pickобъявлен какpublic staticи находится в классе ниже- сохраните порядок параметров, закодированный в дескрипторе
- объявленный возвращаемый тип —
List<String>; дженерики стираются и в дескрипторе не появляются
import java.util.List;
public final class Descriptors {
// javap -s -p -> descriptor: (Ljava/lang/String;[IJ)Ljava/util/List;
// ваш код здесь
}
Допишите реализацию.
Дескриптор перечисляет параметры по порядку внутри скобок, а возвращаемый тип ставит после них, кодируя I как int, J как long, ведущую [ как массив и Lcom/foo/Bar; как ссылочный тип. Значит, здесь это public static List<String> pick(String s, int[] a, long n), а параметр дженерика стёрт. Флаг javap -s печатает дескрипторы, -p добавляет приватные члены.
- ✗Читать возвращаемый тип до скобок, а не после них
- ✗Ждать, что аргументы дженериков появятся в дескрипторе, — они стираются
- ✗Забывать, что
javapскрывает приватные члены, пока не передан-p
- →Что
javap -cпоказывает о методе такого, чего не показываетjavap -s? - →Где внутри class-файла выживает обобщённый тип
List<String>, если не в дескрипторе?
Решение
import java.util.List;
public final class Descriptors {
public static List<String> pick(String s, int[] a, long n) {
return List.of(s);
}
}
javap -s -p Descriptors печатает:
public static java.util.List<java.lang.String> pick(java.lang.String, int[], long);
descriptor: (Ljava/lang/String;[IJ)Ljava/util/List;
Как читать дескриптор. Внутри скобок — параметры по порядку, после скобок — возвращаемый тип. Односимвольные коды: Z boolean, B byte, C char, S short, I int, J long, F float, D double, V void (только для возврата). Ссылочный тип — L<внутреннее/имя>;, массив — ведущая [ перед типом элемента. Отсюда Ljava/lang/String; → String, [I → int[], J → long, а возврат Ljava/util/List; → List.
Дженерики в дескрипторе не живут: он хранит только стёртые типы. Обобщённый List<String> уцелел в отдельном атрибуте Signature — именно его javap использует, чтобы напечатать java.util.List<java.lang.String> в строке сигнатуры над дескриптором.
Полезные флаги: -s печатает дескрипторы, -p включает приватные члены, -c дизассемблирует байткод, -v добавляет пул констант и таблицы кадров.