Comments 15
По декомпилированному коду видно, что полученный синглтон похож на eager реализацию синглтона, он создается в тот момент, когда класслоудер загружает класс.
Ну да, но это не проблема, класс-то все равно загрузится в момент первого обращения, так что можно считать это lazy-реализацией.
А, пардон, значит, неправильно Ваш посыл понял. Мне показалось, что Вы сказали это в том ключе, мол, реализация eager, значит это не настоящий синглтон.
Eager вполне себе нормальный синглтон) Вообще как по мне "ненастоящим" синглноном можно назвать только инстанс образованный какой-нибудь DI библиотекой в скоупе Singleton)
Несколько моментов:
- Часто можно смотреть не только Kotlin->ByteCode->Java, а еще и скомпиленный JS. Но, конечно, учитывать, что бэкенды разные.
- Интересно посмотреть, как сделаны замыкания.
- Интересно посмотреть, как сделаны всякие около-reflection штуки. И тут Kotlin->ByteCode->Java не поможет. На банальном
println(::main)
отсыпется - Интересно посмотреть во что всякие конструкторы
inner
превращаются
Ну то есть всё в целом ожидаемо, но интересно.
На банальном println(::main) отсыпется
Уже не должен, по идее. Накидайте пожалуйста примеров, которые вам интересно было бы посмотреть, я их потестирую. Только лучше полными/компилирующимися примерами — так как Котлина не знаю, к сожалению, могу только скормить пример как есть.
Уже не должен, по идее.
Почему "уже"? Почему "не должен"?
Полный код:
fun main(args: Array<String>) {
println(::main)
}
Код компилируется, работает. Вывод:
fun main(kotlin.Array<kotlin.String>): kotlin.Unit
Байткод показывается нормально.
Если его прогнать Show bytecode и Decompile, то там некомпилируемая шляпа:
public static final void main(@NotNull String[] args) {
Intrinsics.checkParameterIsNotNull(args, "args");
<undefinedtype> var1 = null.INSTANCE;
System.out.println(var1);
}
Но это, пожалуй, простительно. Function references завязаны на reflection, а с ним в Котлине с всё непросто: приходится поддерживать и интероп с java, и js/native/ir, и котлиновые фичи (локальные функции, например). Это прослеживается и в трекере и в документации, особенно если посмотреть на JS.
Если его прогнать Show bytecode и Decompile, то там некомпилируемая шляпаУгу, потому что параметер 'vac' (VERIFY_ANONYMOUS_CLASSES) по умолчанию неактивен. В результате декомпилятор считает класс анонимным, который им на самом деле не является. Если активировать, то результат выглядит так:
public static final void main(@NotNull String[] args) {
Intrinsics.checkParameterIsNotNull(args, "args");
final class NamelessClass_1 extends FunctionReference implements Function1 {
public static final NamelessClass_1 INSTANCE = new NamelessClass_1();
public final void invoke(@NotNull String[] p1) {
Intrinsics.checkParameterIsNotNull(p1, "p1");
TestPrintlnKt.main(p1);
}
public final KDeclarationContainer getOwner() {
return Reflection.getOrCreateKotlinPackage(TestPrintlnKt.class, "main");
}
public final String getName() {
return "main";
}
public final String getSignature() {
return "main([Ljava/lang/String;)V";
}
NamelessClass_1() {
super(1);
}
}
NamelessClass_1 var1 = NamelessClass_1.INSTANCE;
System.out.println(var1);
}
во-первых не всегда код будет декомпилирован корректно, во-вторых не любой код может быть декомпилирован
В теории практически любой (правда не всегда потом рекомпилируется, но это немного другой вопрос). В 99% случаев если что-то не (или неверно) декомпилируется, то это баг или недоработка. Если есть примеры подобного, дайте пожалуйста.
Почему декомпилировалось со странным (Function0)null.INSTANCE; — я без понятия, вероятнее всего это баг декомпилятора.Это не баг, просто часть функционала сейчас по умолчанию отключена (см. пример выше, то же самое). Надо включить параметр 'vac', тогда получится:
public final class Test {
public final void test() {
final class NamelessClass_1 extends Lambda implements Function0 {
public static final NamelessClass_1 INSTANCE = new NamelessClass_1();
public final void invoke() {
String var1 = "hello";
System.out.println(var1);
}
NamelessClass_1() {
super(0);
}
}
Function0 action$iv = (Function0)NamelessClass_1.INSTANCE;
action$iv.invoke();
String var2 = "world";
System.out.println(var2);
}
}
Kotlin под капотом — смотрим декомпилированный байткод