scala学习笔记-面向对象编程(类、对象、继承、特质)

1:类
1.1:定义类:
  • scala是支持面向对象的,也有类和对象的概念。
  • 说明
    • var name:String = _, _表示使用默认值进行初始化
    • val变量不能使用_来进行初始化,因为val是不可变的,所以必须手动指定一个默认值
    • main方法必须要放在一个scala的object(单例对象)中才能执行
// 定义一个Customer类,并添加成员变量/成员方法
// 添加一个main方法,并创建Customer类的对象,并给对象赋值,打印对象中的成员,调用成员方法
class Customer {
  var name:String = _
  var sex:String = _
  val registerDate:Date = new Date

  def sayHi(msg:String) = {
    println(msg)
  }
}

object Main {
  def main(args: Array[String]): Unit = {
    val customer = new Customer
    //给对象的成员变量赋值
    customer.name = "张三"
    customer.sex = "男"

    println(s"姓名: ${customer.name}, 性别:${customer.sex}, 注册时间: ${customer.registerDate}")
    //对象调用方法  
    customer.sayHi("你好!")
  }
}
1.2:构造器:
  • 主构造器:主构造器是指在类名的后面跟上一系列参数
class 类名(var/val 参数名:类型 = 默认值, var/val 参数名:类型 = 默认值){
    // 构造代码块
}
  • 辅助构造器:在类中使用this来定义
def this(参数名:类型, 参数名:类型) {
    ...
}
  • 示例:
class Student(val name:String, val age:Int) {
    
   val address:String="beijing" 
  // 定义一个参数的辅助构造器
  def this(name:String) {
    // 第一行必须调用主构造器、其他辅助构造器或者super父类的构造器
    this(name, 20)
  }

  def this(age:Int) {
    this("年龄", age)
  }
}
2:对象
2.1:scala中的object
  • scala中是没有Java中的静态成员的。如果将来我们需要用到static变量、static方法,就要用到scala中的单例对象object
  • 定义object:定义单例对象和定义类很像,就是把class换成object
  • 说明
    • 使用object 单例对象名定义一个单例对象,可以用object作为工具类或者存放常量
    • 在单例对象中定义的变量,类似于Java中的static成员变量
    • 在单例对象中定义的方法,类似于Java中的static方法
    • object单例对象的构造代码可以直接写在花括号中
    • 调用单例对象的方法,直接使用单例对象名.方法名,访问单例对象的成员变量也是使用单例对象名.变量名
    • 单例对象只能有一个无参的主构造器,不能添加其他参数
  • 示例
object DateUtils {

  // 在object中定义的成员变量,相当于Java中定义一个静态变量
  // 定义一个SimpleDateFormat日期时间格式化对象
  val simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm")

  // 构造代码
  println("构造代码")
    
  // 相当于Java中定义一个静态方法
  def format(date:Date) = simpleDateFormat.format(date)

  // main是一个静态方法,所以必须要写在object中
  def main(args: Array[String]): Unit = {
      
    println { DateUtils.format(new Date()) };
  }
}
2.2:scala中的伴生对象
  • 同一个scala文件,有一个class和object具有同样的名字,那么就称这个object是class的伴生对象,class是object的伴生类,伴生类和伴生对象的最大特点是,可以相互访问
  • 说明
    • 伴生类和伴生对象的名字必须是一样的
    • 伴生类和伴生对象需要在一个scala源文件中
    • 伴生类和伴生对象可以互相访问private的属性
  • 示例
class ClassObject {
  val id = 1
  private var name = "itcast"
  def printName(): Unit ={
    //在Dog类中可以访问伴生对象Dog的私有属性
    println(ClassObject.CONSTANT + name )
  }


}

object ClassObject{
  //伴生对象中的私有属性
  private val CONSTANT = "您好 : "
  def main(args: Array[String]) {
    val p = new ClassObject
    //访问私有的字段name
    p.name = "123"
    p.printName()
  }
}
2.3:scala中object的apply方法
  • 伴生对象的apply方法用来快速地创建一个伴生类的对象
  • 说明
    • 当遇到类名(参数1, 参数2…)会自动调用apply方法,在apply方法中来创建对象
    • 定义apply时,如果参数列表是空,也不能省略括号(),否则引用的是伴生对象
  • 示例
class Person(var name:String, var age:Int) {

  override def toString = s"Person($name, $age)"
}

object Person {
  // 实现apply方法
  // 返回的是伴生类的对象
  def apply(name:String, age:Int): Person = new Person(name, age)

  // apply方法支持重载
  def apply(name:String):Person = new Person(name, 20)

  def apply(age:Int):Person = new Person("年龄", age)

  def apply():Person = new Person("年龄", 20)
}

object Main2 {
  def main(args: Array[String]): Unit = {
    val p1 = Person("张三", 20)
    val p2 = Person("李四")
    val p3 = Person(100)
    val p4 = Person()

    println(p1)
    println(p2)
    println(p3)
    println(p4)
  }
}
2.4: scala中object的main方法
  • scala和Java一样,如果要运行一个程序,必须有一个main方法,而在Java中main方法是静态的,而在scala中没有静态方法
  • 在scala中,这个main方法必须放在一个object中
object Main1{
  def main(args:Array[String]) = {
    println("hello, scala")
  }
}
  • 也可以继承自 Trait(特质),然后将需要编写在main方法中的代码,写在object的构造方法体内。其本质是调用了Trait这个特质中的main方法
3:继承
3.1 继承extends
class Student extends Persion{
}
3.2 override和super
  • 可以使用override关键字来重写一个val字段
  • 可以使用super关键字访问父类的成员
class Persion{
	val name = 'superName'
	def getName =name
}

class Student extends Persion{
	//重写val字段
	override val name String= "child"
	//重写getName方法
	override def getName:String = "hi ,"+super.getName
}
3.3:isInstanceOf和asInstanceOf
  • isInstanceOf:判断对象是否为指定的对象
  • asInstanceOf:将对象转换成指定类型
javaScala
判断对象是否为C类型obj instanceof Cobj.isInstanceof[C]
将对象强转成C类型(C)objobj.asInstanceof[C]
获取类型为T的class类型C.classclassOf[C]
3.4:getClass和classOf
  • isInstanceOf 只能判断出对象是否为指定类及其子类的对象,而不能精确判断出,对象就是指定的对象。如果要求精确地判断出对象就是指定类的对象,那么只能使用getClass和classOf
    • 对象.getClass可以精确的获取对象的类型
    • classOf[类型] 可以精确获取类型
    • 使用==操作符就可以直接比较
3.5:访问修饰符
  • java中的访问控制,通样适用于scala,可以在成员前面添加private/protected关键字来控制成员的课件行。但是在scala中没有public关键,任何没有被private/protected修饰的成员变量都是公共的
  • private[this]
    • 被修饰的成员只是在当前类中被访问。可以理解为只能通过this.来访问
  • protected[this]
    • 被修饰的成员只是在当前类和当前类子类中被访问。可以理解为通过this.来访问或者子类通过this.访问
3.6:调用父类的constructor
  • 实例化子类对象,必须调用父类的构造器,在scala中,只能在子类的主构造器中调用父类结构器
  • 示例
class Persion(var name:String){
	print("name:"+name)
}
class student(name:String,var clazz:String) extends Persion(name)
3.7:抽象类
  • 如果类的某个成员在当前类的定义是不完整的,它就是一个抽象类
  • 两种情况
    • 方法没有方法体
    • 变量没有初始化
  • 没有方法体的方法称为抽象方法,没有初始化的变量称为抽象字段。定义抽象类和java一样,在类前面加上abstract关键字
  • 示例
abstract class Persion(val name:string){
	// 抽象方法
	def say:String
	// 抽象字段
	val address:String
}
3.8:匿名内部类
  • 匿名内部类是没有名字的子类,直接用来穿件实例对象。
abstract calss Persion{
	// 抽象方法
	def say:unit
}
object Test{
	 def main(args: Array[String]): Unit = {
		val p1=new Persion{
			override defsay:unit= println("匿名内部类")
		}
		p1.say
	}
}
4: trait特质
4.1 作为接口使用
  • 使用 extends来继承trait
  • 如果要继承多个trait,则使用with关键字
  • 示例
trait Persion{
	// 抽象方法
	def say(msg:String)
}
class Student extends Persion{
	override def log(msg:String):Unit =print(msg)
}
4.2:定义具体的方法
  • 和类一样,trait 中可以定义具体的方法
  • 示例
trait Persion{
	// 抽象方法
	def say(msg:String)=print(msg)
}
4.3:定义具体的方法和抽象方法
  • 在trait 中,可以混合使用具体方法和抽象方法
  • 使用具体方法依赖于抽象方法,而抽象方法可以放到继承trait 的子类中实现,这种设计方式也称为模板模式
  • 示例
trait Logs{
	// 抽象方法
	def log(msg:String)
	//具体方法:该方法依赖于抽象方法log
	def info(msg:String)=log("INFO"+msg:String)
	def warn(msg:String)=log("WARN"+msg:String)
	def error(msg:String)=log("REEOR"+msg:String)
}
class ConsoleLogs extends Logs{
	override def log(msg:String):Unit=print(msg)
}
4.4:定义具体字段和抽象字段
  • 在trait 中可以定义具体字段和抽象字段
  • 继承trait 的子类自动拥有trait 中定义的字段,字段直接被添加到子类中
  • 示例
trait logs{
	// 具体字段
	val sdf =new SimpleDateFormat("yyyy-MM-dd HH:mm")
	val Info ="信息:"+sdf.format(new Date)
	// 抽象字段
	val TYPE:String
	// 抽象方法
	def log(msg:string)
}
class ConsoleLog extends logs{
	// 实现抽象方法
	override val TYPE:String ='kongzhitai'
	// 实现抽象方法
	override def(msg:String):Unit=print(s"$TYPE$Info $msg")
}
4.5:实例对象混入trait
  • trait 还可以混入到实例对象中,给对象实例增加额外的行为,只有混入了trait 的对象才具有trait中的方法,其他的类对象不具有trait 中的行为
  • 使用with将trait 混入到实例对象中
trait logs{
	def log(msg:string)=print(msg)
}
class UserService
object Test{
	def main(args: Array[String]): Unit = {
		var UserService =new UserService with logs
		UserService.log("hello") 
	}
}
4.5:trait 调用链
  • 责任链模式
    -在这里插入图片描述
  • 示例
    在这里插入图片描述
  • 类继承trait 后,可以依次调用多个trait 中的同一个方法,只要trait 中的同一个方法在最有都依次执行super关键字即可。类中调用多个trait 中都有这个方法时,首先会从最右边的trait 方法开始执行,然后依次往左执行,形成一个调用链
// 数据处理
trait Handler{
	def handel(data:String){
		print("处理数据")
	}
}
trait DataValid extents Handler{
 override def handel(data:String){
		print("验证数据")
		super.handel(data)
	} 
}

trait SignatureValid extents Handler{
 override def handel(data:String){
		print("签名检查")
		super.handel(data)
	} 
}

class PaymentService extents DataValid with SignatureValid {
 def pay(data:String){
		print("支付数据")
		this.handel(data)
	} 
}
4.6:trait 构造机制
  • trait也有构造代码,单和类不一样,trait不能有构造器参数
  • 每一个trait只有一个无参的构造器
  • 一个类继承另一个类、以及多个trait,点创建类的实例对象时,构造顺序如下:
    • 1):执行父类的构造器
    • 2):从左到右依次执行trait的构造器
    • 3):如果trait有父trait,先构造父trait,如果多个trait有同样的父trait,只初始化一次
    • 4):执行子类构造器
4.7:trait 继承class
  • trait也可以继承class
    • 继承的class会成为所有trait子类的超级父类
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值