Scala 中 object、class 与 trait 的区别
引言
当你刚入门 Scala,肯定会迫不及待想要编写自己的第一个 Scala 程序。如果你已经在交互模式下敲过 Scala 代码,想必你更乐意尝试在 IDEA 下写 Scala 代码。当你打开 IDEA,满心期待的创建自己的第一个 Scala 工程,接着创建一个 Scala 类,如下:
你会发现这里有好几种类型,如果你之前学过 Java,你会毫不犹豫选择第一个 Class 类型,然后快速写下如下代码:
class MyFirstScala {
def main(args: Array[String]): Unit = {
prinln("hello scala")
}
}
当你正打算运行这个 main 方法时,却发现无法执行,我猜你肯定当时就郁闷了。
要让 main 方法执行其实很简单,只需要将 class 改为 object 即可,如下:
object MyFirstScala {
def main(args: Array[String]): Unit = {
prinln("hello scala")
}
}
这到底是怎么回事呀?
object
单例对象概念
我们都知道 Scala 与 Java 一样,是一种面向对象的编程语言;但是 Scala 却与 Java 有所不同,就是 Scala 具有直接创建对象的能力,该对象无需类即可定义其成员。
什么意思呀?就是不需要定义 class 类,也不需要 new,就能直接创建一个对象。而且创建对象的方式和定义类的方式是一样的,唯一的区别就是创建对象要使用 object 关键字。
通过 object 直接创建的对象,我们称为单例对象。 为何叫单例对象,因为单例对象是没有类就可以存在的对象,这样的对象是独一无二的,不像通过 class 方式可以 new 无数的对象。
那为何 Scala 中程序入口 main() 方法一定要放在 object 创建的单例对象中执行,而不能像 Java 一样?
许多面向对象的编程语言包括 Java 都是使用 static 关键字修饰 main() 方法,这样 main() 方法就变成了类静态方法,这样在类加载完成后就可以直接调用 main() 方法了。
但是,Scala 根本就没有 static 关键字, 也没有类静态方法和静态属性。这就是为什么在 Scala 中 main() 方法只能放在 object 定义的单例对象中执行。
单例对象定义
object singleton_objname {
// object code , member functions and fields.
}
注意:object 不能提供构造器参数,也就是说 object 必须是无参的
单例对象用法
object findsum{
var a = 56
var b = 21
def sum(): Int ={
return a+b;
}
}
object Main
{
def print(){
printf("The sum is : "+ findsum.sum());
}
def main(args: Array[String])
{
print();
}
}
伴生对象和伴生类
如果类和单例对象具有相同的名称,那么该类为该对象的同伴类,而该对象为该类的伴生对象 。
伴生对象与伴生类在 Scala 的面向对象编程方法中占据极其重要的位置,主要用于代替 Java 静态成员变量与静态方法,很多 Scala 工具方法都是采用单例对象或伴生对象实现的。
伴生类与伴生对象可以互相访问彼此的私有属性或方法,但是必须都在同一源文件
class companion{
var a = 23;
var b = 78;
def sum(){
println("The sum is: "+ (a+b));
}
}
object companion{
def main(args:Array[String]){
new companion().sum();
}
}
class
Scala 是一种面向对象的编程语言,所以其定义和使用类的方式和 Java 基本相同,不过 Scala 也有一些不同的地方之处
构造器
-
主构造器
Scala 中每个类都有且只有一个主构造器,且主构造器会执行类定义中的所有语句
class Student(val name: String,val age: Int){ // 括号中的就是主构造器的参数 println("Primary constructor") // 该语句属于主构造器的一部分 ... }
只有主构造器的参数才会被编译成字段,其初始化的值为构造时传入的参数。
可以在主构造器中使用默认参数,可防止辅助构造器使用过多。
class Student(val name: String = "",val age: Int = 0){ // 主构造器的默认参数 ... }
-
辅助构造器
辅助构造器的名称为 this
class Student { private var name = " " private var age = 0 def this(name: String){ //辅助构造器1 this() //调用主构造器 this.name = name } def this(name: String,age: Int){ //辅助构造器2 this(name) //调用前一个辅助构造器 this.age = age } }
每个辅助构造器都必须以一个对先前已定义的其他辅助构造器或主构造器的调用开始
-
私有构造器
想要让主构造器变成私有构造器,只需要加上 private 关键字即可
class Dog private(val age: Int) { ... }
这样做之后,就必须使用辅助构造器来构造 Dog 对象了
属性(成员变量)
scala 对每个类属性或成员变量都会提供 getter 和 setter 方法,同时也可以显示的声明,但是针对 val 类型,只提供getter 方法,默认情况下,字段为 public 类型
trait
在 Scala 中 trait(特征) 相当于 Java 的接口,与接口不同的是它还可以定义属性和方法的实现,这一点又更像 Java 的抽象类。
一般情况下 Scala 的类只能够继承单一父类,但是如果是 trait(特征) 的话就可以继承多个,从结果来看就是实现了多重继承。
trait Person {
def getInfo(): String
}
class Man(var name: String, var age: Int) extends Person {
override def getInfo(): String = {
s"info:name=${name},age=${age}"
}
}
总结
在 Scala 中,object 用于定义单例对象,class 用于定义类,trait 用于定义接口。至于还有两个 case class / case object 类型,主要用于支持模式匹配。