簡體   English   中英

Kotlin 類屬性和 Java 類字段有什么區別

[英]What are the differences between Kotlin class properties and Java class fields

我已經開始學習 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 屬性的示例。

例子

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 ,它只創建一個 getter。 當屬性是var ,它會創建一個 getter 和一個 setter。 並且該字段默認變為private ,如上面的代碼所示, discountprivate 但是您可以使用其 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 執行類似的操作。


就是這樣! 希望有幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM