【问题标题】:What are the differences between Kotlin class properties and Java class fieldsKotlin 类属性和 Java 类字段有什么区别
【发布时间】:2019-06-22 22:13:57
【问题描述】:

我已经开始学习 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 中存在的东西并且可能是欺骗性的东西)

【问题讨论】:

  • 对于有Java背景和学习Kotlin的人来说,这个比较真的很有用,谢谢!

标签: java kotlin properties field


【解决方案1】:

我想详细说明 Java 字段和 Kotlin 属性之间的区别。查看以下 Java 字段和 Kotlin 属性示例。

示例

Java 字段:

class Product {
    public int discount = 20;
}

Kotlin 属性:

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 时,它只创建一个 getter。当属性是var 时,它会同时创建一个getter 和一个setter。 如上代码所示,该字段默认变为privatediscountprivate。但是您可以使用它的 getter 和 setter 访问 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() 方法对getter 做类似的事情。


就是这样!希望对您有所帮助。

【讨论】:

    猜你喜欢
    • 2019-07-17
    • 2018-04-28
    • 2021-12-26
    • 1970-01-01
    • 2015-09-10
    • 2012-04-24
    • 2021-09-03
    • 1970-01-01
    相关资源
    最近更新 更多