一、构造对象
1.1构造器
//Scala类有一个构造方法比其他所有的构造方法都更为重要,我们称之为主构造器,其他的构造器我们称之为辅助构造器
- 主构造器的声明直接放置于类名之后
class ConstructorClass() { // 类体 } val obj = new ConstructorClass() // 当使用new构建对象时,等同于调用类的主构造器 //构造对象时,会执行主构造函数,所谓的主构造函数,其实就是类的主体内容。 |
- 主构造器会执行类定义中的所有语句
class ConstructorClass() { // 执行主构造器时,类体中所有语句都会执行 } val obj = new ConstructorClass() |
- 主构造器传递参数
// 如果主构造器无参数,小括号可省略,构建对象时调用的构造方法的小括号也可以省略。
// 构造器也是方法(函数),传递参数和使用方法和前面的函数部分内容没有区别 class ConstructorClass( p : String ) { println("参数为 = " + p) } val obj = new ConstructorClass("123") |
- 辅助构造器名称为this(这个和Java是不一样的),多个辅助构造器通过不同参数列表进行区分
class Person() { private var sname = "" private var iage = 0 // 辅助构造器无论是直接或间接,最终都一定要调用主构造器,执行主构造器的逻辑。在辅助构造中一定要有调主构造器的逻辑。 def this( name : String ) { this() // 放在第一行 sname = name } def this( name : String, age : Int ) { this(name) //调用之前已经声明过该构造器,必须在之前调用 iage = age } } |
- 如果想让主构造器变成私有的,可以在()之前加上private,这样用户只能通过辅助构造器来构造对象了
class ConstructorClass private () { } |
注意:辅助构造器的声明不能和主构造器的声明一致,会发生错误
1.2apply方法
//因为伴生对象可以处理静态资源,所以完全可以通过伴生对象提供的方法对伴生类进行处理
//一个调用时不用加方法名的快捷函数,一般用来构造对象。
object Person {//这个伴生对象的类是Person$ def apply() = { return new Person() } } … val p = Person() // 此处不需要使用new关键字,而是直接增加小括号,在执行时,会自动调用伴生对象中的apply方法。返回伴生类实例对象 |
//利用apply完成工厂方法 object AdvApply { |
1.3构造器方法
//Scala类的主构造器函数是可以添加参数的。如果参数未用任何修饰符修饰,那么这个参数是局部变量
class Person( name : String ) { // 此处的name未加任何修饰,是局部变量,无法通过对象进行访问 } var p = new Person("lisi") println(p.name)//错误 |
//如果参数使用val关键字声明,那么Scala会将参数作为类的只读属性(不能修改)使用
class Person( val name : String ) { } var p = new Person("lisi") println(p.name) //正确 这里调用对象的name属性,其实并不是属性,而是方法,因为方法无参数,所以省略了小括号,感觉和调用属性一样,这体现了Scala语言访问一致性 |
//如果参数使用var关键字声明,那么Scala会将参数作为类的成员属性使用,并会提供属性对应的setter/getter方法
class Person( var name : String ) { } var p = new Person("lisi") p.name = "wangwu" // setter println(p.name) //getter |
二、包
2.1包对象
//包可以包含类、对象和特质trait,但不能包含函数或变量的定义。很不幸,这是Java虚拟机的局限。为了弥补这一点不足,scala提供了包对象的概念来解决这个问题
package com.atguigu.scala package object advance { 这样在同一个包下的其他类,或者引用该包的类都可以直接使用,包对象中定义的方法和参数了。 |
2.2可见性
//在Java中,访问权限分为四种:public, private(同类),protected(同类,同包,子类), 缺省的(同类,同包)。在Scala中,你可以通过类似的修饰符达到同样的效果。但是使用上有区别
- 当访问权限缺省时,scala默认为public访问权限(相当于java中的public)
- 私有权限 :private(相当于java中的private) 此时属性为私有的,只在类的内部和伴生对象中可用
- 受保护权限:protected // scala中受保护权限比Java中更严格,只能子类访问,同包无法访问
- 包访问权限:private[scala](表示属性有了限制。同时包也有了限制,类似java中的缺省) // 增加包访问权限后,private同时起作用。不仅同类可以使用,[]中包下其他类也可以使用
- 伴生类与伴生对象之间的访问可以不受可见性约束,即使是private也可以访问。
三、继承
//和Java一样使用extends关键字,在定义中给出子类需要而超类没有的字段和方法,或者重写超类的方法。
如果类声明为final,他将不能被继承。如果单个方法声明为final,将不能被重写
注意:scala明确规定,只要出现override情况,一定要显式声明关键字override
3.1重写方法
重写一个非抽象方法需要用override修饰符,调用超类的方法使用super关键字
class Person { var name : String = "zhangsan" def printName() { println(name); } } class Emp extends Person { override def printName() { println(name); } } |
3.2类型检查和转换
要测试某个对象是否属于某个给定的类,可以用isInstanceOf方法。用asInstanceOf方法将引用转换为子类的引用。classOf获取对象的类名。
println("Hello".isInstanceOf[String])//true println("Hello".asInstanceOf[String])//Hello println(classOf[String]) ================================================== 1) classOf[String]就如同Java的 String.class 2) obj.isInstanceOf[T]就如同Java的obj instanceof T 3) obj.asInstanceOf[T]就如同Java的(T)obj |
3.3匿名子类
//和Java一样,你可以通过包含带有定义或重写的代码块的方式创建一个匿名的子类:
好处是可以临时覆写父类的方法,而只对当前对象有影响,不影响其他实例的对象。
var customer:Customer=new Customer{ |
四、特质
//所有的面向对象的语言都不允许直接的多重继承,因为会出现“deadly diamond of death”问题。Scala提供了特质(trait),特质可以同时拥有抽象方法和具体方法,一个类可以实现多个特质。
//特质中没有实现的方法就是抽象方法。类通过extends继承特质,通过with可以继承多个特质。
4.1带有具体实现的特质
和Java中的接口不太一样的是特质中的方法并不一定是抽象的,也可以有默认实现
4.2动态混入
除了可以在类声明时继承特质以外,还可以在构建对象时混入特质,扩展目标类的功能
4.3特质链
由于scala支持多个特质的继承,因此必然会产生不同特质同名方法的冲突问题。有解决了构建对象的同时如果混入多个特质,那么特质声明顺序从左到右,方法执行顺序从右到左
4.4特质构造顺序
特质也是有构造器的,构造器中的内容由“字段的初始化”和一些其他语句构成。
注意:步骤总结:
1)、调用当前类的超类构造器
2)、第一个特质的父特质构造器,如果已经执行过,就不再执行
3)、第一个特质构造器
4)、第二个特质构造器的父特质构造器, 如果已经执行过,就不再执行
5)、第二个特质构造器
6)、当前类构造器