欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

大数据之scala_scala之面向对象

程序员文章站 2022-07-12 13:09:29
...

类和对象详解

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

构造器

构造器的定义
每个类都有一个主构造器,这个构造器和类定义"交织"在一起类名后面的内容就是主构造器,
如果参数列表为空的话,()可以省略
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方法

成员方法/函数

在类的成员位置定义的函数或者方法是类的成员的一部分
大数据之scala_scala之面向对象

局部变量

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

**
  * 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] 指定本包以及本包的父包可以访问 指定属性访问的包范围
大数据之scala_scala之面向对象
大数据之scala_scala之面向对象
方法的访问权限和类的访问权限
访问现象和属性的现象一致
通用于主构造器,辅构造器,以及普通方法
默认权限是共有的
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,可以当作消息进行传递

相关标签: scala 大数据