Об этом уже сообщается в YouTrack, как KT-16681 , "kotlin позволяет изменять поле свойства только для чтения".
Как вы можете видеть в ответе в KT-16681, пользовательский метод получения скомпилирован в другую функцию, в результате чего поле foo
и метод getFoo()
становятся двумя несвязанными вещами.
Также из ответа в KT-16681 это нарушение вида (Переназначение чтения-only свойство через поле поддержки) приведет к ошибке, так как Kotlin 1.3.
Обновление: В комментарии оригинальный автор упоминал, что KT-16681
отличается от этого вопроса.Однако, вдохновленный этой проблемой, мы можем видеть там байт-код Kotlin Tools -> Kotlin -> Show Kotlin Bytecode
(удаленные метаданные и т. Д.):
public final class Test53699029Kt {
// access flags 0xA
private static I counter
// access flags 0x19
public final static getCounter()I
L0
LINENUMBER 3 L0
GETSTATIC Test53699029Kt.counter : I
IRETURN
L1
MAXSTACK = 1
MAXLOCALS = 0
// access flags 0x19
public final static setCounter(I)V
L0
LINENUMBER 3 L0
ILOAD 0
PUTSTATIC Test53699029Kt.counter : I
RETURN
L1
LOCALVARIABLE <set-?> I L0 L1 0
MAXSTACK = 1
MAXLOCALS = 1
// access flags 0x19
public final static getFoo()Ljava/lang/String;
@Lorg/jetbrains/annotations/NotNull;() // invisible
L0
LINENUMBER 7 L0
GETSTATIC Test53699029Kt.counter : I
DUP
ISTORE 0
ICONST_1
IADD
PUTSTATIC Test53699029Kt.counter : I
L1
LINENUMBER 8 L1
NEW java/lang/StringBuilder
DUP
INVOKESPECIAL java/lang/StringBuilder.<init> ()V
LDC "val"
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
GETSTATIC Test53699029Kt.counter : I
INVOKEVIRTUAL java/lang/StringBuilder.append (I)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
ARETURN
L2
MAXSTACK = 2
MAXLOCALS = 1
// access flags 0x19
public final static main()V
L0
LINENUMBER 12 L0
INVOKESTATIC Test53699029Kt.getFoo ()Ljava/lang/String;
ASTORE 0
L1
LINENUMBER 13 L1
INVOKESTATIC Test53699029Kt.getFoo ()Ljava/lang/String;
ASTORE 1
L2
LINENUMBER 14 L2
INVOKESTATIC Test53699029Kt.getFoo ()Ljava/lang/String;
ASTORE 2
L3
LINENUMBER 15 L3
NEW java/lang/StringBuilder
DUP
INVOKESPECIAL java/lang/StringBuilder.<init> ()V
LDC "we got: "
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
ALOAD 0
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
BIPUSH 32
INVOKEVIRTUAL java/lang/StringBuilder.append (C)Ljava/lang/StringBuilder;
ALOAD 1
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
BIPUSH 32
INVOKEVIRTUAL java/lang/StringBuilder.append (C)Ljava/lang/StringBuilder;
ALOAD 2
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
ASTORE 3
L4
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ALOAD 3
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V
L5
L6
LINENUMBER 17 L6
RETURN
L7
LOCALVARIABLE c Ljava/lang/String; L3 L7 2
LOCALVARIABLE b Ljava/lang/String; L2 L7 1
LOCALVARIABLE a Ljava/lang/String; L1 L7 0
MAXSTACK = 2
MAXLOCALS = 4
// access flags 0x1009
public static synthetic main([Ljava/lang/String;)V
INVOKESTATIC Test53699029Kt.main ()V
RETURN
MAXSTACK = 0
MAXLOCALS = 1
Как мы видим, для foo
нет поля, просто getFoo()
, сравнение для обычного объявления val
:
public final class Test53699029Kt {
// access flags 0xA
private static I counter
// access flags 0x19
public final static getCounter()I
L0
LINENUMBER 1 L0
GETSTATIC Test53699029Kt.counter : I
IRETURN
L1
MAXSTACK = 1
MAXLOCALS = 0
// access flags 0x19
public final static setCounter(I)V
L0
LINENUMBER 1 L0
ILOAD 0
PUTSTATIC Test53699029Kt.counter : I
RETURN
L1
LOCALVARIABLE <set-?> I L0 L1 0
MAXSTACK = 1
MAXLOCALS = 1
// access flags 0x1A
private final static Ljava/lang/String; foo = "aaa"
@Lorg/jetbrains/annotations/NotNull;() // invisible
// access flags 0x19
public final static getFoo()Ljava/lang/String;
@Lorg/jetbrains/annotations/NotNull;() // invisible
L0
LINENUMBER 3 L0
GETSTATIC Test53699029Kt.foo : Ljava/lang/String;
ARETURN
L1
MAXSTACK = 1
MAXLOCALS = 0
// access flags 0x19
public final static main()V
L0
LINENUMBER 6 L0
GETSTATIC Test53699029Kt.foo : Ljava/lang/String;
ASTORE 0
L1
LINENUMBER 7 L1
GETSTATIC Test53699029Kt.foo : Ljava/lang/String;
ASTORE 1
L2
LINENUMBER 8 L2
GETSTATIC Test53699029Kt.foo : Ljava/lang/String;
ASTORE 2
L3
LINENUMBER 9 L3
NEW java/lang/StringBuilder
DUP
INVOKESPECIAL java/lang/StringBuilder.<init> ()V
LDC "we got: "
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
ALOAD 0
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
BIPUSH 32
INVOKEVIRTUAL java/lang/StringBuilder.append (C)Ljava/lang/StringBuilder;
ALOAD 1
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
BIPUSH 32
INVOKEVIRTUAL java/lang/StringBuilder.append (C)Ljava/lang/StringBuilder;
ALOAD 2
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
ASTORE 3
L4
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ALOAD 3
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V
L5
L6
LINENUMBER 11 L6
RETURN
L7
LOCALVARIABLE c Ljava/lang/String; L3 L7 2
LOCALVARIABLE b Ljava/lang/String; L2 L7 1
LOCALVARIABLE a Ljava/lang/String; L1 L7 0
MAXSTACK = 2
MAXLOCALS = 4
// access flags 0x1009
public static synthetic main([Ljava/lang/String;)V
INVOKESTATIC Test53699029Kt.main ()V
RETURN
MAXSTACK = 0
MAXLOCALS = 1
// access flags 0x8
static <clinit>()V
L0
LINENUMBER 3 L0
LDC "aaa"
PUTSTATIC Test53699029Kt.foo : Ljava/lang/String;
RETURN
MAXSTACK = 1
MAXLOCALS = 0
с использованием val foo = "aaa"
даст нормальное поле final static String foo
и метод final static String getFoo()
, но использование val foo: String
с get()
не будетсоздайте это поле, просто создайте метод.Эта функция получения генерируется Kotlin, я полагаю, что потеря поля происходит из-за потери первоначального назначения в объявлении val
, но я не могу найти реальную документацию по этому вопросу, такую как Getters and Setters вKotlin просто прямо использует этот вывод.
Итак, кажется, что это обходной путь для модификации final static
.
Проблемы возникают, когда неизменяемое поле ссылается на изменяемое поле.val
не может быть переназначено, но оно ссылается на var
, поле, которое можно переназначить, это приводит к изменению val
.