【发布时间】:2019-01-25 07:54:18
【问题描述】:
我想问一下下面这两个类声明有什么区别。
class Person(name: String, age: Int)
或
class Person() {
var name: String = ""
var age: Int = 0
}
【问题讨论】:
标签: scala class declaration
我想问一下下面这两个类声明有什么区别。
class Person(name: String, age: Int)
或
class Person() {
var name: String = ""
var age: Int = 0
}
【问题讨论】:
标签: scala class declaration
class Person(name: String, age: Int)
name 和 age 是构造函数参数。因此它们是:
Person 实例class Person() {
var name: String = ""
var age: Int = 0
}
name 和 age 是类数据成员。它们是:
Person 实例赋予相同的默认值var 变量那么,有什么区别呢?几乎所有东西。
【讨论】:
Person(name: String, age: Int) 不会将 name 和 age 添加为类成员(甚至不是私有成员),除非它们在方法中使用(因为编译器必须存储该值某处)。如果只在构造时使用它们来声明其他变量,则参数将永远不会成为类成员。在这些情况下,它们仍然是方法(构造函数)的简单参数,因此谈论它们是公共/私有(或可变/不可变,但如果您尝试改变参数,即使编译器也会提到 vals)可能会令人困惑。
name 和age 描述为“不可变”和“私有”可能在@987654336 的每个非病理情况下更有用@ 和 age 实际上在 Person 的某个地方使用。如果使用它们(可能是大多数时候),它们确实是作为privatefinal 字段实现的。试试class Person(name: String, age: Int) { override def toString = name + age }; classOf[Person].getDeclaredFields。
第一个声明使用name和age作为构造函数参数,但是它们并没有成为类的成员,也就是说你不能写person.name。
对于初学者来说,第二行可以认为是写class Person(var name: String = " ", var age: Int = 0)的更复杂的方式。它实际上并没有转化为完全相同的东西:您的版本创建一个具有单个构造函数参数和两个公共变量的类,而我的版本具有一个具有 2 个具有默认值的参数的构造函数。除非您有充分的理由以自己的方式声明它,否则通常最好这样写:
val person = new Person("Andrew", 11)
比
val person = new Person()
person.name = "Andrew"
person.age = 11
这是您的第二个版本会强制您执行的操作。
请注意,在 Scala 中,您将主要使用值(常量)而不是变量,因此您实际上通常会使用 class Person(val name: String = " ", val age: Int = 0)。对于像这样的简单数据类型,人们通常使用case class:
case class Person(name: String, age: Int)
在这种情况下,两个参数都被认为是公开的和不可变的。修改人名的唯一方法是使用新名称创建另一个 Person 实例:
val andrew = Person("Andrew", 11)
val will = andrew.copy(name="Will") # Will is also 11
案例类将自动为您提供正确的equals 和hashCode 实现,以及我上面使用的copy 方法。您可以在互联网上轻松找到有关它们的更多信息。
【讨论】:
class P2(var name: String = " ", var age: Int = 0) 创建了一个类 P2,它带有一个相当复杂的构造函数和两个默认参数,而原来的 class P1() { var name: String = " "; var age: Int = 0 } 创建了一个具有更简单的 nullary 构造函数的类。