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

时间:2019-06-22 22:13:57

标签: java kotlin properties field

我已经开始学习Kotlin。我当前的背景是Java。我发现Kotlin中的类属性与Java中的类字段完全不同,即使它们看起来很相似。在他的问题中,我希望将两者之间的所有技术差异汇总在一起。这是我已经知道的:

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

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

class A {
    public String name = "A";
    public void printMessage() {
        System.out.println("Field accessed in method declared inside class A invoked form an object of " + getClass() + " : " + name);
    }
}

class B extends A{
    public String name = "B";
}

public class Main {
    public static void main(String... args){
        B b = new B();
        System.out.println("Field from instance of class B pointed by reference to B : " + b.name);
        A a = b;
        System.out.println("Field from instance of class B pointed by reference to A : "+a.name);
        a.printMessage();
    }
}

打印此内容:

Field from instance of class B pointed by reference to B : B
Field from instance of class B pointed by reference to A : A
Field accessed in method declared inside class A invoked form an object of class B : A

相反,Kotlin属性是由自动生成的getter和setter访问的字段。属性会被覆盖(而不是隐藏),因此可以在运行时解析属性访问,并且具有与上面用Kotlin编写的含义相似的代码:

open class A {
    open val name = "A"
    fun printMessage() {
        println("Field accessed in method declared inside class A invoked form an object of $javaClass : $name")
    }
}

class B(override val name : String = "B") : A()

fun main(args : Array<String>) {
    val b : B = B()
    println("Field from instance of class B pointed by reference to B : " + b.name)
    val a : A = b;
    println("Field from instance of class B pointed by reference to A : " + a.name)
    a.printMessage()
}

打印此内容:

Field from instance of class B pointed by reference to B : B 
Field from instance of class B pointed by reference to A : B 
Field accessed in method declared inside class A invoked form an object of class B : B

访问级别
Java字段是软件包–默认情况下为私有。默认情况下,Kotlin属性是公开的。

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

每个Kotlin类属性的创建方式都必须允许其在访问时提供明确给定的值。 可以通过初始化器,构造器,设置器,延迟初始化来实现这一点:

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

但是必须提供应返回的值-不提供默认值。

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

(我不是在谈论诸如委托属性之类的其他功能,而是乍一看类似于Java中存在的并且可能引起误解的那些东西)

1 个答案:

答案 0 :(得分:0)

我想详细介绍一下Java字段和Kotlin属性之间的区别。看看下面的Java字段和Kotlin属性示例。

示例

Java字段:

class Product {
    public int discount = 20;
}

科特琳属性:

class Product { 
    var discount: Int = 20
}

自动生成的访问器

以上两个示例并不等效。因为在Kotlin中,将自动为属性生成getter和setter。上面的Kotlin属性等效于以下Java代码:

class Product {
    private int discount = 20;

    public int getDiscount() {
        return discount;
    }

    public void setDiscount(int port) {
        this.discount = discount;
    }
}

因此Java字段与Kotlin属性之间的区别在于 Kotlin属性创建了一个字段及其访问器。当该属性为val时,它仅创建一个吸气剂。当属性为var时,它将同时创建一个getter和一个setter。 并且默认情况下,该字段变为private,如上面的代码所示,discountprivate。但是,您可以使用其{{}}和getter来访问discount


自定义访问器

如果我们想在Kotlin的getter和setter中实现一些逻辑或验证该怎么办?例如,当有人在产品上设置discount时,我们要确保其值不超过85%。在这种情况下,我们可以为discount属性定义自定义访问器,如下所示:

class Product {
    var discount: Int = 20
        set(value) {
            if (value >= 85) {
                field = 85
            } else {
                field = value
            }
        }
}

field是Kotlin中的保留关键字,它将值保留为后备字段。上面的代码导致:

product.discount = 70;
println(product.discount) // 70
product.discount = 90;
println(product.discount) // 85

我们可以使用get()方法对吸气剂进行类似的操作。


就是这样!希望有帮助。