Kotlin是“按值传递”还是“按参考传递”?

时间:2017-06-13 07:32:52

标签: kotlin

据我所知,Java是this post的传值。我来自Java背景我想知道Kotlin用于传递两者之间的值。例如ExtensionsMethods

6 个答案:

答案 0 :(得分:22)

每当我听到“传递价值”与“传递参考”Java辩论时,我总是这么认为。我给出的答案:“Java传递引用的副本(按值传递)”(传递引用)。所以每个人都很开心。我会说Kotlin和基于JVM的一样

答案 1 :(得分:15)

语义与Java相同。

在Java中,当你有一个对象的实例,并将它传递给一个方法时,该方法可以改变该对象的状态,并且当方法完成时,这些更改将被应用于该对象。呼叫站点。

同样适用于Kotlin。

答案 2 :(得分:4)

它使用与Java相同的原理。它始终是按值传递的,您可以想象传递了一个副本。对于原始类型,例如Int显而易见,此类参数的值将被传递到函数中,并且外部变量将不会被修改。请注意,由于Kotlin中的参数的作用类似于val,因此无法重新分配:

fun takeInt(a: Int) {
    a = 5
}

由于无法重新分配a,因此无法编译此代码。

对于对象来说,这有点困难,但它也是按值调用的。如果使用对象调用函数,则其引用的副本将传递给该函数:

data class SomeObj(var x: Int = 0)

fun takeObject(o: SomeObj) {
    o.x = 1
}

fun main(args: Array<String>) {
    val obj = SomeObj()
    takeObject(obj)
    println("obj after call: $obj") // SomeObj(x=1)
}

您可以使用传递给函数的引用来更改实际对象。这将影响您传入的参数。但是,引用本身(即变量的值)将永远不会通过函数调用进行更改。

答案 3 :(得分:3)

在Java基本类型(如int,float,double,boolean)中,它们按值传递给方法,如果您在接收器方法中对其进行修改,则它们不会更改为调用方法。但是,如果属性/变量类型不是基元,则像基元数组或其他类一样,当在方法内部更改它们并将其作为参数接收时,它们也会在调用方方法中更改。 但是对于Kotlin,似乎没有什么是原始的,所以我认为所有内容都是通过引用传递的。

答案 4 :(得分:1)

这可能有点令人困惑。 正确的答案,恕我直言,是所有通过引用传递的,但是不可能进行赋值,所以它类似于在C ++中通过值传递。

请注意,函数参数是常量,即无法分配。

请记住,在Kotlin中没有原始类型。一切都是对象。 当您写时:

var x: Int = 3
x += 10

您实际上创建了一个Int类型的对象,为其分配了值3,并获得了一个名为x的引用或指针。 当你写

x += 10

您将值13的新Int对象重新分配给x。较旧的对象成为垃圾(并被垃圾回收)。

当然,编译器会对其进行优化,在这种特殊情况下不会在堆中创建任何对象,但是从概念上讲,这已得到解释。

那么通过引用函数参数传递是什么意思?

  • 由于无法为函数参数赋值,因此Kotlin中不存在C ++中按引用传递的主要优点。
  • 如果对象(传递给函数)具有更改其内部状态的方法,则它会影响原始对象。
    • Int,String等不存在这种方法。它们是不可变的对象。
  • 将对象传递给函数时,不会生成任何副本。

答案 5 :(得分:0)

请记住,我对 Kotlin 很陌生。在我看来,原语是按值传递的,而对象是按引用传递的。

传递给类的原语默认有效,但例如,如果您从列表中传递一个对象,并且该对象发生变化,则类对象也会发生变化。因为,事实上,它是同一个对象。

此外,如果对象从列表中删除,则类对象仍然是参考。所以它仍然可以因其他地方的引用而改变。

下面的例子解释了。您可以here运行它。

fun main() {
   val listObjects = mutableListOf(ClassB(), ClassB(), ClassB())
   val listPrimitives = mutableListOf(111, 222, 333)

   val test = ClassA()

   test.ownedObject = listObjects[0]
   test.ownedPrimitive = listPrimitives[0]

   println("ownedObject: " + test.ownedObject.isEnabled +", ownedPrimitive: " + 
   test.ownedPrimitive)

   listObjects[0].isEnabled = true
   println("ownedObject: " + test.ownedObject.isEnabled +", ownedPrimitive: " + 
   test.ownedPrimitive)

   listPrimitives[0] = 999
   println("ownedObject: " + test.ownedObject.isEnabled +", ownedPrimitive: " + 
   test.ownedPrimitive)
}

class ClassA {
  var ownedObject: ClassB = ClassB()
  var ownedPrimitive: Int = 0
}

class ClassB {
  var isEnabled = false
}