package com.scala.test
object Test {
def main(args: Array[String]): Unit = {
val p1 = new Person
val p2 = new Person
p1.name = "tom"
p2.name = "jerry"
println(p1.name)
println(p2.name)
}
}
class Person {
var name: String = _
def sayName(): Unit = {
println(this.name)
}
}
此时,代码和静态没有一毛钱关系,p1和p2各自为政,都拥有自己特有的name属性。
如果想要让Person类增加一个静态属性age,即age属性是属于类的,即当修改p1对象的age属性,会导致p2对象的age也修改, 同理如果修改p2对象的age属性,那么也会导致p1对象的age遭到修改!
其实这个也好办,在类的内部增加一个对象即可,p1和p2都有这么个属性,这个属性值就是同一个A对象,如下图:
package com.scala.test
object Test {
def main(args: Array[String]): Unit = {
val p1 = new Person
val p2 = new Person
p1.name = "tom"
p1.a.age = 20 // 这里修改age, 会导致p2对象的age也变为20
p2.name = "jerry"
p2.a.age = 50 // 这里修改age, 会导致p2对象的age也变为50 ps:这样算是变相滴实现了静态属性age
println(p1.name + "\t" + p1.a.age)
println(p2.name + "\t" + p2.a.age)
}
}
class Person {
var name: String = _
val a: A.type = A
def sayName(): Unit = {
println(this.name)
}
}
object A {
var age = 10
def sayAge(): Unit = {
println(age)
}
}
如上图,p1对象和p2对象拥有同一个A实例,修改任何一个对象的age,都会影响到另一个对象的age,这样算是间接滴实现了静态,跟java的静态还不太一样,这里只是用了某些手段实现了静态的功能,这个姑且叫"伪静态"吧
但是又有新问题了,可以看出调用时真麻烦,还得这样调用:p1.a.age 和 p2.a.age, 然后尝试想,p1.a.age 就等价于A.age,可以用类名直接调用!然后就接着想如果那个单例对象的名字也叫做Person, 这样以后调用时,直接调用Person.age岂不是更好, 这样看起来更像是"静态调用" ! 于是就有了如下代码:
package com.scala.test
object Test {
def main(args: Array[String]): Unit = {
val p1 = new Person
val p2 = new Person
p1.name = "tom"
Person.age = 20
p2.name = "jerry"
Person.age = 50
println(p1.name + "\t" + Person.age) // 这样调用看起来更像是"静态调用":动态属性用实例调用, 而静态属性用类名调用
println(p2.name + "\t" + Person.age)
}
}
class Person {
var name: String = _
def sayName(): Unit = {
println(this.name)
}
}
object Person {
var age = 10
def sayAge(): Unit = {
println(age)
}
}
上面代码看起来更像是"静态属性"。ps:scala并没有"静态"的概念,只是通过某种手段实现了"静态"的功能。
上面的代码又出现了新问题, java中静态属性,既可以用类名.属性调用,也可以用对象.属性调用, 而上面的代码只能做到用类名.属性,所以还需要增加对象.属性调用方式,如下图:
package com.scala.test
object Test {
def main(args: Array[String]): Unit = {
val p1 = new Person
val p2 = new Person
p1.name = "tom"
p1.setAge(40)
p2.name = "jerry"
p2.setAge(50)
println(p1.name + "\t" + p1.age) // 这样调用看起来更像是"静态调用":动态属性用实例调用, 而静态属性用类名调用
println(p2.name + "\t" + p2.age)
}
}
class Person {
var name: String = _
def sayName(): Unit = {
println(this.name)
}
def setAge(newAge: Int): Unit = {
Person.age = newAge
}
def age(): Int = {
Person.age
}
}
object Person {
var age = 10
def sayAge(): Unit = {
println(age)
}
}
这样看起来跟java的静态好像又近了一步!
总结:
scala中没有"静态"的概念,所谓的"静态"都是通过某种手段模拟出来的,即通过"单例对象"进行了模拟!
一个class和一个object,当两个名字相同时,一个就叫做"伴生类", 另一个叫做"伴生对象"。
可以通过反编译的方式看下"伴生类"和"伴生对象"在底层生成的.class文件, 基本类似于我上面的代码。
暂时可以这么理解:伴生类中写的属性都是动态的,即每个对象都是独有一份,而半生对象中写的属性是静态的,所有的对象共享这个属性。
既然是静态的了,那么调用时建议用"类名.属性"来调用。
静态方法大致也类似于静态属性。
感兴趣的朋友可以自己写一个"伴生类"和"伴生对象",然后反编译出来看看,细细体会下scala为实现"静态"而使用的"巧妙手法"。