【Scala】基础6:面向对象

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)

猜你喜欢

转载自blog.csdn.net/hr786250678/article/details/86491214