Kotlin 类属性和 Java 类字段有什么区别

Tom*_*asz 9 java field properties kotlin

我已经开始学习 Kotlin。我目前的背景是Java。我发现 Kotlin 中的类属性与 Java 中的类字段有很大不同,尽管它们看起来很相似。在他的问题中,我想收集这两者之间的所有技术差异。这是我\xe2\x80\x99已经弄清楚的:

\n\n

Java 字段和隐藏与 Kotli 属性和覆盖
\n(实际上这促使我写这篇文章):

\n\n

在Java中,基类的字段被派生类中同名的字段隐藏,因此使用哪个字段取决于包含该字段的对象的引用类型,而不是对象本身的类型(字段不像方法那样被重写,因此它们不依赖于对象的运行时类型)。例如这段代码:

\n\n
class A {\n    public String name = "A";\n    public void printMessage() {\n        System.out.println("Field accessed in method declared inside class A invoked form an object of " + getClass() + " : " + name);\n    }\n}\n\nclass B extends A{\n    public String name = "B";\n}\n\npublic class Main {\n    public static void main(String... args){\n        B b = new B();\n        System.out.println("Field from instance of class B pointed by reference to B : " + b.name);\n        A a = b;\n        System.out.println("Field from instance of class B pointed by reference to A : "+a.name);\n        a.printMessage();\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

打印这个:

\n\n
Field from instance of class B pointed by reference to B : B\nField from instance of class B pointed by reference to A : A\nField accessed in method declared inside class A invoked form an object of class B : A\n
Run Code Online (Sandbox Code Playgroud)\n\n

相比之下,Kotlin 属性是由自动生成的 getter 和 setter 访问的字段。属性被覆盖(不是隐藏),因此属性访问在运行时解析,用 Kotlin 编写的与上面含义类似的代码:

\n\n
open class A {\n    open val name = "A"\n    fun printMessage() {\n        println("Field accessed in method declared inside class A invoked form an object of $javaClass : $name")\n    }\n}\n\nclass B(override val name : String = "B") : A()\n\nfun main(args : Array<String>) {\n    val b : B = B()\n    println("Field from instance of class B pointed by reference to B : " + b.name)\n    val a : A = b;\n    println("Field from instance of class B pointed by reference to A : " + a.name)\n    a.printMessage()\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

打印这个:

\n\n
Field from instance of class B pointed by reference to B : B \nField from instance of class B pointed by reference to A : B \nField accessed in method declared inside class A invoked form an object of class B : B\n
Run Code Online (Sandbox Code Playgroud)\n\n

访问级别
\nJava 字段默认为包 \xe2\x80\x93 私有。Kotlin 属性默认是公共的。

\n\n

默认初始化
\nJava 字段使用合理的默认值进行初始化(如下所述:https: //docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html)。

\n\n

每个 Kotlin 类属性都必须以某种方式创建,使其能够在访问时提供显式给定值。\n可以通过初始化器、构造器、setter、延迟初始化来实现这一点:

\n\n
class InitValues(val inCtor : String = "Given in constructor"){\n    var byInitializer = "In initializer"\n    var initializedWithNull : String? = null\n    val valueGivenByGetter\n        get() : String {\n            return "This value is given by getter"\n        }\n    val byLazyInit : String by lazy { "This is lazy init" }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

但应返回的值必须给出 \xe2\x80\x93 ,不会提供默认值。

\n\n

关于类字段/属性是否还有其他技术差异可能会让在 Kotlin 中编写代码的 Java 程序员感到惊讶?

\n\n

(我\xe2\x80\x99m不是在谈论附加功能,例如委托属性,而是那些乍一看与Java中存在的类似并且可能令人迷惑的东西)

\n

Yog*_*ity 14

I would like to elaborate more on the differences between a Java field and a Kotlin Property. Have a look at the following examples of Java field and Kotlin property.

Examples

Java field:

class Product {
    public int discount = 20;
}
Run Code Online (Sandbox Code Playgroud)

Kotlin property:

class Product { 
    var discount: Int = 20
}
Run Code Online (Sandbox Code Playgroud)

Auto-generated Accessors

The two examples above are not equivalent. Because in Kotlin, getters and setters are auto-generated for the properties. The Kotlin property above is equivalent to the following Java code:

class Product {
    private int discount = 20;

    public int getDiscount() {
        return discount;
    }

    public void setDiscount(int discount) {
        this.discount = discount;
    }
}
Run Code Online (Sandbox Code Playgroud)

So the difference between the Java field and Kotlin Property is that the Kotlin property creates a field and its accessors. When the property is a val, it creates a getter only. When the property is a var, it creates both a getter and a setter. And the field becomes private by default as shown in the above code, the discount is private. But you can access the discount using its getters and setters.


Custom Accessors

What if we want to implement some logic or validation inside the getters and setters in Kotlin? For example, when someone is setting the discount on the product, we want to make sure it's never above 85%. In this case, we can define the custom accessors for the discount property like following:

class Product {
    var discount: Int = 20
        set(value) {
            if (value >= 85) {
                field = 85
            } else {
                field = value
            }
        }
}
Run Code Online (Sandbox Code Playgroud)

The field is a reserved keyword in Kotlin which holds the value as a backing field. The above code result in:

product.discount = 70;
println(product.discount) // 70
product.discount = 90;
println(product.discount) // 85
Run Code Online (Sandbox Code Playgroud)

We can do similar things with the getter using the get() method.


That's it! Hope that helps.