可以用class来声明一个类,并用new关键字来创建一个对象。
对于类中的全局变量,必须在声明的时候指定其默认值,否则就会报错。
同时可以在类中定义一系列的方法,方法的定义用def 方法名(参数) :返回值 = {方法体}
class Person { var name:String = "" var age:Int = 0 def printUserInfo(): Unit ={ println("name = "+name , "age = "+age) } def eat(food: String): String = s"$name is eating $food" } object Test{ def main(args: Array[String]): Unit = { val person = new Person() person.printUserInfo() person.name = "张三" person.age = 25 println(person.eat("大闸蟹")) } }对于全局变量,可以用 _ 来表示默认初始值,如下:
class SimpleClass { var a:Int = _ var b:Double = _ var c:Float = _ var d:Long = _ var e:String = _ //对于未知类型的数据使用默认值会直接报错,因为无法进行类型推导 //var f = _ //SimpleClass(0, 0.0, 0.0, 0, null) override def toString = s"SimpleClass($a, $b, $c, $d, $e)" }有时候为了让全局变量私有,我们可以添加 private[this] :
class Cat{ private[this] var name:String = "Lucy" def printName(): Unit ={ println(s"cat name is $name") } } #调用 var cat = new Cat() cat.printName //cat.name 这里获取不到name这个全局变量Scala的构造器和Java的构造器完全不同,Scala的构造器分为主构造器和辅助构造器;
主构造器的参数列表直接写在类名(Class)后面,每个类都有一个主构造器(默认是无参构造器)。主构造器与类的定义交织在一起,除了定义的全局变量和方法,其他都是主构造器的内容,代码如下:
class Teacher(name: String) { println("teacher start") var teachAge: Int = 8 var height:Double = _ val school:String = "广工" println("teacher end") //辅助构造器,第一行必需调用主构造器或者其他已存在的辅助构造器 //并且只能调用在自己之前定义的其他辅助构造器,而不能调用后面定义的辅助构造器(避免死循环调用) //参数不可以用val或var来修饰 def this(name: String, teachAge: Int) { this(name) this.teachAge = teachAge } def this(name: String, teachAge: Int, height: Double) { this(name,teachAge) this.height = height } def teach(): Unit ={ println(s"$name is teaching ...") } } //如果将一个主构造器私有,那么客户端是无法获取该对象的 class Student private(name: String) object ConstructorDemo { def main(args: Array[String]): Unit = { val t1 = new Teacher("孔子") println(s"teach age is ${t1.teachAge}") var t2 = new Teacher("老子", 5) println(s"teach age is ${t2.teachAge}") var t3 = new Teacher("孙子", 3,1.65d) println(s"teach age is ${t3.teachAge}") } }一个类如果想继承其他的类,就必须调用其构造器,无论主构造器还是辅助构造器;在实例化该类的时候,首先会调用父类的构造器,再调用本身的构造器。
构造器传入的参数默认为val类型的数据,类的内部无法修改变量值,只能获取。
class SeniorTeacher(name: String, desc: String,teachAge: Int) extends Teacher(name, teachAge) { println("SeniorTeacher start") println(desc) //desc = "" //被重写的属性必须是val修饰的属性 override val school:String = "北大" override def teach(): Unit ={ println(s"$name SeniorTeacher is teaching ...") } println("SeniorTeacher end") } val t1 = new SeniorTeacher("小孔", "教龄18",18) println(t1.school) t1.teach抽象函数的声明:
抽象函数必须使用abstract修饰;抽象函数的全局变量可赋值也可不赋值;抽象函数可有有一个或多个方法未实现;继承抽象函数:
继承抽象函数时,没有赋值的属性必须赋值,没有实现的方法必须实现在实现属性/方法的时候可以使用override关键字,但是不使用也可以。被继承的抽象类属性不能使用var来修饰,这样做的好处是防止父类修改子类重写的属性。 abstract class Order { val oid: Long val name: String val price: Double def orderInfo } class WaitPayOrder extends Order { override val oid: Long = 100001L override val name: String = "" override val price: Double = 100.0d override def orderInfo: Unit = { println("oid = " + oid, "name = " + name, "price = " + price) } } object AbstractClassDemo { def main(args: Array[String]): Unit = { val waitPayOrder = new WaitPayOrder println(waitPayOrder.oid) waitPayOrder.orderInfo } }trait 类似于 Java 的 interface ,其用法与abstract class一致,只不过abstract class可以使用构造器而trait不可以, 用法如下:
trait Person{ var name:String var age:Int def speak(): Unit ={ println("speak...") } def eat } class Student extends Person{ override var name: String = _ override var age: Int = _ override def eat: Unit = { print(s"$name is eating...") } }什么时候应该使用trait而不是抽象类? 如果你想定义一个类似接口的类型, 你可能会在trait和抽象类之间难以取舍. 这两种形式都可以让你定义一个类型的一些行为, 并要求继承者定义一些其他行为. 一些经验法则:
优先使用trait. 一个类扩展多个trait是很方便的, 但却只能扩展一个抽象类.
如果你需要构造函数参数, 使用抽象类. 因为抽象类可以定义带参数的构造函数, 而trait不行.
假如一个class与object同时修饰ObjectDemo,此时class ObjectDemo叫做object ObjectDemo的伴生类;而object ObjectDemo叫做class ObjectDemo的伴生对象,如下:
class ObjectDemo { } object ObjectDemo{ } object Test { def main(args: Array[String]): Unit = { val o1 = new ObjectDemo val o2 = ObjectDemo //(o1 = ObjectDemo@5ebec15,o2 = ObjectDemo$@21bcffb5) println("o1 = " + o1, "o2 = " + o2) } }伴生对象是一个单例对象:
object ObjectDemo { var element = 0 def increase { element += 1 } } //调用如下 for (i <- 1 to 10) { ObjectDemo.increase } println(ObjectDemo.element) //10通过伴生对象的apply方法实现对象的初始化(如果调用伴生对象(),则会间接apply()方法,可以在该方法中实现对象的初始化 ):
object ObjectDemo { def apply() = { new ObjectDemo } ... } //调用如下 val od1 = ObjectDemo() val od2 = ObjectDemo() //(od1 = ObjectDemo@5ebec15,od2 = ObjectDemo@21bcffb5) println("od1 = " + od1, "od2 = " + od2)