1.1 类参数
在scala中,可以直接在类名后面指定类参数,这就像在定义函数时函数参数跟在函数名后面一样,可以在实例化对象时完成初始化
如果在类参数前加上了val或var,那么类参数也变成了类的属性,可以使用对象.属性名访问
scala中定义属性和方法还可以使用和Java一样的思路,不赘述。
举例1:普通定义类属性和方法
class Person{
var name:String = "" //这样定义类属性时一定要赋初始值,因为scala的类属性不会像Java一样有默认值
var age:Int =100
def info() = {
s"${name} 今年 ${age} 岁"
}
}
val p:Person = new Person
p.name = "小明"
p.age=18
println(p.info())
举例2:使用类参数
class Person(n:String,a:Int){
var name:String = n
var age:Int =a
def info() = {
s"${name} 今年 ${age} 岁"
}
}
val p:Person = new Person("小明",18)
println(p.info())
举例3:使用类参数定义属性
class Person(var name:String,var age:Int){
def info() = {
s"${name} 今年 ${age} 岁"
}
}
val p:Person = new Person("小明",18)
println(p.info())
1.2 构造器
Scala的构造器分为主构造器和辅助构造器(或者称为从构造器),与Java构造不同之处在于Scala不需要定义与类名相同的方法作为构造器。
主构造器:主构造器的参数列表直接写在类名后面,构造器的内容定义在类里面。所以,一个Scala类中,除了属性、方法以外的代码都是主构造器的内容。
举例:
class Person(var name:String,var age:Int){
println("这里是主构造器的内容。。。")
def info() = {
s"${name} 今年 ${age} 岁"
}
}
new Person("小明",18)
辅助构造器:以def this命名的函数为辅助构造器,辅助构造器可以有多个,参数没有限制,而且辅助构造器里可以调用其他辅助构造器或主构造器,但最终一定是调用主构造器。
举例:
class Person(var name:String,var age:Int){
println("这里是主构造器的内容。。。")
def info() = {
s"${name} 今年 ${age} 岁"
}
def this(name:String) = {
this(name,10000) //调用主构造器
}
def this(age:Int) = {
this("小韩",age) //调用主构造器
}
def this() = {
this("小赵") //调用辅助构造器
}
}
1.3 内部类
Scala中内部类是属于外部类的实例化对象的。
class outerClass(val name:String) {
class innerClass(val name:String){
def showInfo() = {
s"outerClass:${outerClass.this.name} \n innerClass:${name}"
}
}
}
val oc = new outerClass("外部类")
val ic = new oc.innerClass("内部类")
println(ic.showInfo())
1.4 类别名
class outerClass(val name:String) {
oc=>
class innerClass(val name:String){
ic=>
def showInfo() = {
s"outerClass:${oc.name}\ninnerClass:${ic.name}"
}
}
}
1.5 继承
在Scala中,一个类可以使用extends关键字扩展最多一个其他类,另外可以用override关键字覆盖所继承的方法,类中的字段和方法可以用this关键字访问,父类中的字段和方法可以用super关键字访问。
举例:
class A{
def hi = "Hello from A"
override def toString = getClass.getName
}
class B extends A
class C extends B{
override def hi = "hi from C "+super.hi
}
val hiA = new A().hi
val hiB = new B().hi
val hiC = new C().hi
1.6 抽象类
在一个类当中,如果至少有一个属性或方法只声明而没有具体定义,那么这个属性或方法就叫抽象的,对应的类就叫做抽象类。
抽象类由abstract关键字指定,是将由其他类扩展的一个类,而自己不能实例化。
abstract class Animal() {
val height:Double = 1.78
val weight:Double
def drink()
}
abstract class car{
val year:Int
val automatic:Boolean = true
def color: String
}
class RedMini(val year:Int) extends car{
override def color: String = {
s"$year"
}
}
1.7 apply方法
名为“apply”的方法有时是指它要作为一个默认方法或一个注入方法,可以直接调用而不需要方法名。
apply方法实际上是一个快捷方式,可以使用小括号功能而不需要方法名,相当于初始化。
就是说,把一个类的实例化对象当作函数去使用,就相当于调用了apply方法,这也就是为什么List、Map、Set在取某一个元素时使用的是小括号而不是中括号。
class testApply{
def apply(name:String) = {
println(s"=========${name}=============")
}
}
ta.apply("海尔兄弟")
ta("海尔兄弟")
1.8 懒值
类中使用的字段(值和变量)都是在类第一次实例化时创建的。不过,懒值则只在第一次实例化这些值时才创建。(是不是觉得很熟悉,这不就相当于传名参数和传值参数么。。。)
lazy val x = {println("now x"); 5}
val y = {println("creating y");3}
println(x)
println(y)
1.9 Object类(对象)
这里的对象指的不是类的实例化对象,而是一个类类型,只能有不超过1个实例,在面向对象设计中称为一个单例,对象不能用new关键字创建实例,只需要按名直接访问,相当于静态类。
(类一共有三个类型:Class、Object和Trait,Trait会在后面提到)
object Hello{
println("hello")
def hi = "hi"
}
println(Hello.hi)
1.10 伴生对象和伴生类
伴生对象是与类同名的一个对象,与类在同一个文件中定义,二者互为伴生。
为类提供一个伴生对象,在Scala中是一个常见的模式,另外还可以由此得到一个特性:从访问控制的角度讲,他们可以相互访问私有和保护字段及方法。
上面提到了可以自己定义apply方法,其实apply方法也有默认,默认返回的是伴生类的实例化对象。
def apply(): testObj = new testObj()
我们还没有看到伴生对象带来的好处,也就是与伴生类共享的特殊的访问控制,类会访问其伴生对象的私有成员。
举例:
class DBConnection{
private val props = Map("url" -> DBConnection.url,"user" -> DBConnection.user,"password" -> DBConnection.password) //这里的DBConnection是伴生对象
println("url:"+ props("url"))
}
object DBConnection{
private val url = "jdbc://localhost"
private val user = "tiger"
private val password = "scort"
def apply(): DBConnection = new DBConnection
def main(args: Array[String]): Unit = {
DBConnection()
}
}
1.11 case类
当一个类被定义成为case类后,Scala会自动帮你创建一个伴生对象并自动实现了一系列方法。
方法名 | 位置 | 描述 |
apply | 伴生对象 | 这是一个工厂方法,用于实例化case类 |
copy | 伴生类 | 返回实例的一个副本,并完成所需的修改。参数是类的字段,默认值设置为当前字段值 |
equals | 伴生类 | 如果另一个实例中的所有字段与这个实例中的所有字段匹配,则返回true,也可以用操作符==来调用。 |
hashCode | 伴生类 | 返回实例字段的一个散列码,对基于散列的集合很有用 |
toString | 伴生类 | 将类名和字段呈现为一个String |
unapply | 伴生对象 | 将实例抽取到一个字段元组,从而可以使用case类实例完成模式匹配 |
举例:
case class Check(name:String,isThief:Boolean)
object Check{
def main(args: Array[String]): Unit = {
val h = Check("tom",true)
println(h)
val r = h.copy(name = "jerry")
println(r)
println(h == r)
val res = h match{
case Check(x,true) => s"$x is a thief"
case Check(x,false) => s"$x is not a thief"
}
println(res)
}
}
1.12 Trait类
Trait是一种支持多重继承的类。类,对象都只能扩展不超过一个类,但是可以同时扩展多个Trait,使用with关键字,相当于java里的接口。
和Object一样,Trait定义的类也不能实例化
如果一个类定义为Class D extends A with B with C ,最右侧的类是当前类的直接父类,继承关系依次向左,extends后是最高的父类。(C是D的父类,B是C的父类,A是B的父类)
class Base{
override def toString = "Base"
}
trait A extends Base{
override def toString = "A->" + super.toString()
}
trait B {
override def toString = "B->" + super.toString()
}
trait C {
override def toString = "C->" + super.toString()
}
class D extends Base with A with B with C{
override def toString = "D->" + super.toString()
}
val d = new D()
println(d)