大数据之scala_scala之面向对象

类和对象详解

组成结构
构造函数
成员变量
成员方法(函数)
局部变量
代码块

构造器

构造器的定义
每个类都有一个主构造器,这个构造器和类定义"交织"在一起类名后面的内容就是主构造器,
如果参数列表为空的话,()可以省略
scala的类有且仅有一个主构造器,要想提供更加丰富的构造器,就需要使用辅助构造器,辅助构造器是可选的,它们叫做this
注意:主构造器会执行类定义中的所有语句

例子一

class User { // 类默认有一个无参的主构造函数
}
val user = new User

例子二

class User2(val name: String, age: Int) { // 两个参数的主构造函数

}

val user2 = new User2("jim", 23)
user2.name // 使用val修饰的变量默认是成员变量对象可以访问
// user2.age   // age没有使用val或者var修饰 所以不能被访问

例子三

class User3 {
   var name: String = _
   var age: Int = _
  // 辅助构造函数
  def this(name: String, age: Int) {
    // 构造函数中的首行必须调用主构造函数或者其他构造函数
    this()
    this.name = name
    this.age = age
  }
  // 辅助构造函数
  def this(msg: String) = {
    // 首行调用一个构造
    this("ww", 12)
    println(msg)
  }
}
val u1 = new User3()
val u2 = new User3("")
val u3 = new User3("lisi", 23)
println(u3.name)

总结:
1,有两类构造器:主构造器,辅助构造器
2,构造器的定义位置
主构造器和类交织在一起,class Student2(val name: String, var age: Int)
3, 辅助构造器是一个特殊的方法,定义在类中 def this(name:String,age:Int,gender:String)
4,辅助构造器,第一行必须调用主构造器(或者其他的辅助构造器)
5,辅助构造器的参数不能和主构造器的参数完全一致(参数个数,参数类型,参数顺序)
6,可以定义空参的辅助构造器,但是主构造器的参数必须进行初始化赋值
7,作用域:辅助构造器的作用域,只在方法中,主构造器的作用域是类中除了成员属性和
成员方法之外的所有范围(可以通过反编译查看源码)
构造器的参数说明

主构造器的参数没有使用var/val修饰 ,那么他的参数就是局部变量
val修饰的构造函数的参数是类的成员私有属性 ,只读
var修饰的构造函数的参数是类的私有成员属性 ,但是是可读可写的

成员变量

定义在类中的变量称为成员变量

// 1 主构造函数中使用val 和 var修饰的变量为成员变量
class Person(val address:String) {
  // 2 val 修饰的变量默认只有getter方法   一要初始化
  val name:String = "val修饰这里必须赋值"
  // 3 var 修饰的变量默认有 get和set方法  直接点属性操作  使用 _ 占位可以稍后赋值
  var age:Int= _  // 占位可以稍后赋值
  // 4 @BeanProperty会生成getMsg setMsg方法
  @BeanProperty  
  var msg:String =  _
}

主构造函数中使用val 和 var修饰的变量为成员变量
val 修饰的变量默认只有getter方法 一要初始化
var 修饰的变量默认有 get和set方法 直接点属性操作 使用 _ 占位可以稍后赋值
@BeanProperty会生成getMsg setMsg方法

成员方法/函数

在类的成员位置定义的函数或者方法是类的成员的一部分
在这里插入图片描述

局部变量

定义在函数/方法的参数中 , 定义在代码块中 , 定义在流程控制的条件表达式中

**
  * x:Int*  可变参数
  * x在方法的参数中是局部变量
  * sum 定义在方法体中是局部变量  且使用前要初始化
  * @param x
  * @return
  */
def add(x: Int*): Int = {
  // 局部变量  在使用之前必须初始化
  var sum: Int = 0
  for (e <- x) {
    sum += e
  }
  sum
}
{
  println("hello tom")
  var x:String="必须赋值"
  println(x)

}

注意 :
1 局部变量都需要设置初始值
2 局部变量的作用范围 ,定义在代码块中

代码块

在类或者对象中的代码块在实例化的时候会被调用

{
  println("hello tom")
  var x:String="必须赋值"
  println(x)

}

伴生类和伴生对象

条件 1:在同一个源文件中, 条件 2:对象名和类名相同

*类名和object的名称一致
  * 类是对象的伴生类
  * 对象是类的伴生对象

class Demo6(val name: String) {
}
object Demo6 {
}

伴生对象和伴生类之间可以互相访问彼此的私有属性和私有方法

class Demo{
  val id = 1
  private var name = "xiaoqing"
  def printName(): Unit ={
    //在 Dog 类中可以访问伴生对象 Dog 的私有属性
    println(Demo.CONSTANT + name )
  }
}
/**
  * 伴生对象
  */
object Demo{
  //伴生对象中的私有属性
  private val CONSTANT = "汪汪汪 : "
  def main(args: Array[String]) {
    val p = new Demo
    //访问私有的字段 name
    p.name = "123"
    p.printName()
  }
}

apply方法

使用此方法时,可以在main函数中不通过new来创建一个对象,即可以不用专门的一次一次地进行实例化,加载创建对象的这个类的时候,会自动调用apply这个方法,类似Java中的static静态块。

建议将这个方法写在半生对象中 , 如果将这个方法写在一个没有半生对象的类中是无法使用的

class Demo (){

  private var age :Int=_

  def this( name : String , age : Int ){
    this()
    this.age=age
  }

}
object Demo{
  //使用apply方法new Demo对象
  def apply(): Demo = new Demo()

  //apply方法可以重写
  def apply(name:String,age:Int): Demo = new Demo(name,age)

  def main(args: Array[String]): Unit = {
    //Demo()就表示了new出来的Demo对象,可以直接调用Demo中的属性,没有参数时,括号也不能省略
    //使用该方法获取属性时,且只能获取,不能赋值,即只提供了get方法,没提供set方法
    Demo().age=123
    println(Demo().age)  // 0
    
    //通过构造器给对象赋值
    println(Demo("zss", 18).age)  // 18
  }
}

注意:
1 apply方法的主要目的是不使用new来获取实例对象, 并且默认是单例的!!!
2.apply方法建议编写在伴生对象中
3.apply方法如果没有参数也不要省略(),否则会报错

classOf、isInstanceOf、asInstanceOf

classOf[T]看成Java里的T.class
isInstanceOf[T]判断是否是[T]实例对象
obj.asInstanceOf[T]强制类型转换

class object的选择

class object 一般情况下,使用 object + 伴生的 class
1,优先使用object,object本质上拥有了的类的所有特性,object中没有构造器,也没有 参数 ,必须要有程序入口,object,main方法,必不可少
2, 如果是单例的,优先选择object,如果是多例的(封装数据,构造器),必须选择类
3, 伴生类和伴生对象都会用到。首先把object写上,如果需要有类的功能,就把伴生类 写上。

权限修饰符

scala中的权限修饰符public protected private 默认情况下使用的public任何范围都可以访问
private 修饰的属性或者方法的访问范围是本类和伴生对象中

scala中有更加严格的访问权限的控制

private [this] ,作用域为当前类中,伴生对象中无效
private [packageName] 指定包及其子包有效

属性的访问权限

class User(val name: String, private var age: Int) {

  def show() = {
    // 本类中可以访问柱构造函数中定义的私有的属性age
    // 本类也可以访问伴生对象中的私有属性
    println(name + ":" + age + ":" + User.address)
  }

}

object User {
  private val address: String = "wewq"
  def main(args: Array[String]): Unit = {
    val user = new User("ZSS", 21)
    user.show()
    // 伴生对象中也可以访问伴生类中的私有属性
    println(user.name + "--" + user.age)
  }
}

外部不能访问私有属性

object Test1 {
  def main(args: Array[String]): Unit = {
    val user = new User("zss",21)
    // 外部可以访问非私有的属性
    user.name
    // 在外部不能访问私有的尚需经age
    user.age
    //外部不能访问对象中私有的属性
    User.address
  }
}

private[this] 修饰的内容只能本类访问 , 伴生对象和类不能访问

/ 私有构造函数不允许外部new 对象 但是在半生对象中可以
class Person private (val name:String) {
  // 者变量只能本类访问  this
  private[this] val age = 21
  private val addres:String = "Beijing"
}
object  Person{
  def main(args: Array[String]): Unit = {
    val p = new Person("zss")
    p.age
    p.addres
  }
}

this[package] 指定本包以及本包的父包可以访问 指定属性访问的包范围
在这里插入图片描述
在这里插入图片描述
方法的访问权限和类的访问权限
访问现象和属性的现象一致
通用于主构造器,辅构造器,以及普通方法
默认权限是共有的
private 作用域为类和其伴生对象
private [this] ,作用域为当前类中,伴生对象中无效
private [packageName] 指定包及其子包有效 包名的写法,直接写报名,不需要层级路径
主构造器上一样适用于该方法的访问权限
private [cn.edu360.day03] 错误的
private [day03] 正确的
protected
protected 修饰的属性 方法 在类及其伴生对象中有效,在子类及其子类的伴生对象中有效,其他地方无效。

特质

特质使用
Trait(特质)相当于 java 的接口。比接口功能更强大。特质中可以定义属性和抽象方法和方法的实现。
Scala 的类只能够继承单一父类,但是可以实现(继承,混入)多个特质(Trait)使用的关
键字是 with 和 extends
注意 特使不能有主构造函数

**
  * 特质1 
  */
trait T1 {
  val name:String = "我是特质"
  def add(x:Int)
  def show(desc:String)={
    println(desc)
  }
}

/**
  * 特质1 
  */
trait  T2{
  def show()
  
}
// 实现多个特质  
class Demo extends  T1 with T2{
  // 实现接口中的抽象方法
  override def add(x:Int): Unit = {
    
  }
  // 实现抽象方法  override 关键字可以省略
  // 除非想要重写特质类中的非抽象方法时,可以使用override重写该方法
  def show(): Unit = {}
}

动态混入

在使用的时候再实现具体的接口重写对应的抽象方法

class A {
}
class B{
  def  haha={
    // 动态混入 在使用的时候再实现具体的接口重写对应的抽象方法
    val a = new A with T1 with T2 {
      override def add(x: Int): Unit = ???
      override def show(): Unit = ???
    }
  }
}

抽象类

在 Scala 中, 使用 abstract 修饰的类称为抽象类. 在抽象类中可以定义属性、未实现的方法
(抽象方法)和具体实现的方法。 含有抽象方法的类就是抽象类
抽象类中的属性
抽象方法
具体实现的方法
类的单继承

/*
* abstract 修饰的类是一个抽象类
* */
abstract class Animal {
  println("Animal's constructor ....")
  // 定义一个 name 属性
  val name: String = "animal"
  // 没有任何实现的方法
  def sleep()
  // 带有具体的实现的方法
  def eat(f: String): Unit = {
    println(s"$f")
  }}

样例类

使用case修饰的类就是样例类
1 构造器中的参数默认是val修饰的
2 样例类会自动创建伴生对象, 同时在里面实现;的apply和unapply方法 ,创建对象的时候不用new
3 很好的支持匹配模式
4 默认实现了自己的toString , hashCode , copy , equals方法
5.样例类中的参数,默认是val修饰的,所以创建参数时,可以不用写val或var

// 定义一个样例类
case class Person(name:String , var age:Int) {
}

样例类:使用 case 关键字 修饰的类,重要的特征就是支持模式匹配,多例
样例 object:使用 case 关键字修饰的对象,支持模式匹配,单例
case class 和 class 的一些区别:
case class 在初始化的时候,不用 new,而普通类初始化时必须要 new。
case class 重写了 toString 方法。 默认实现了 equals 和 hashCode
case class 实现了序列化接口 with Serializable
case class 支持模式匹配(最重要的特征),所有 case class 必须要有参数列表
有参数用 case class,无参用 case object
case class,和 case object,可以当作消息进行传递

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值