大数据之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,可以当作消息进行传递
上一篇: scala之面向对象
下一篇: 第二节 python语言基础