我已经开始学习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中存在的并且可能引起误解的那些东西)
答案 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
,如上面的代码所示,discount
是private
。但是,您可以使用其{{}}和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()
方法对吸气剂进行类似的操作。
就是这样!希望有帮助。