对象

object 相当于 class 的单个实例,通常在里面放一些静态的 field 或者 method;在 Scala 中没有静态方法和静态字段,但是可以使用 object 这个语法结构来达到同样的目的。
object 作用:

  • 1.存放工具方法和常量
  • 2.高效共享单个不可变的实例
  • 3.单例模式
package com.zy.scala.cls

class Session {}

object SessionFactory {
//该部分相当于 java 中的静态块
val session = new Session //在 object 中的方法相当于 java 中的静态方法
def getSession(): Session = {
session
}
} object SingletonDemo {
def main(args: Array[String]) {
//单例对象,不需要 new,用【单例对象名称.方法】调用对象中的方法
val session1 = SessionFactory.getSession()
println(session1)
//单例对象,不需要 new,用【单例对象名称.变量】调用对象中成员变量
val session2 = SessionFactory.session
println(session2)
}
}

伴生对象

如果有一个 class 文件,还有一个与 class 同名的 object 文件,那么就称这个 object是 class 的伴生对象,class 是 object 的伴生类;伴生类和伴生对象必须存放在一个.scala 文件中;伴生类和伴生对象的最大特点是,可以相互访问。

package com.zy.scala.cls

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

Scala 中的 apply 方法

object 中非常重要的一个特殊方法,就是 apply 方法;

apply 方法通常是在伴生对象中实现的,其目的是,通过伴生类的构造函数功能,来实现伴生对象的构造函数功能;
通常我们会在类的伴生对象中定义 apply 方法,当遇到类名(参数 1,...参数 n)时 apply 方法会被调用;
在创建伴生对象或伴生类的对象时,通常不会使用 new class/class() 的方式,而是直接使用 class(),隐式的调用伴生对象的 apply 方法,这样会让对象创建的更加简洁;

package com.zy.scala.cls

/**
* Array 类的伴生对象中,就实现了可接收变长参数的 apply 方法,
* 并通过创建一个 Array 类的实例化对象,实现了伴生对象的构造函数功能
*/
// 指定 T 泛型的数据类型,并使用变长参数 xs 接收传参,返回 Array[T] 数组
// 通过 new 关键字创建 xs.length 长的 Array 数组
// 其实就是调用 Array 伴生类的 constructor 进行 Array 对象的初始化
// def apply[T: ClassTag](xs: T*): Array[T] = {
// val array = new Array[T](xs.length)
// var i = 0
// for (x <- xs.iterator) { array(i) = x; i += 1 }
// array
// }
object ApplyDemo {
def main(args: Array[String]) {
//调用了 Array 伴生对象的 apply 方法
//def apply(x: Int, xs: Int*): Array[Int]
//arr1 中只有一个元素 5
val arr1 = Array(5)
//new 了一个长度为 5 的 array,数组里面包含 5 个 null
var arr2 = new Array(5)
println(arr1.toBuffer)
}
}

继承

Scala 中,让子类继承父类,与 Java 一样,也是使用 extends 关键字;

继承就代表,子类可继承父类的 field 和 method ,然后子类还可以在自己的内部实现父类没有的,子类特有的 field 和method,使用继承可以有效复用代码;

子类可以覆盖父类的 field 和 method,但是如果父类用 final 修饰,或者 field 和 method 用 final 修饰,则该类是无法被继承的,或者 field 和 method 是无法被覆盖的。

private 修饰的 field 和 method 不可以被子类继承,只能在类的内部使用;

field 必须要被定义成 val 的形式才能被继承,并且还要使用 override 关键字。 因为 var 修饰的 field 是可变的,在子类中可直接引用被赋值,不需要被继承;即 val 修饰的才允许被继承,var 修饰的只允许被引用。继承就是改变、覆盖的意思。

Java 中的访问控制权限,同样适用于 Scala

类内部

本包

子类

外部包

public

protected

×

default

×

×

private

×

×

×

package com.zy.scala.extends_demo

class Person {
val name = "super" def getName = this.name
} class Student extends Person {
//继承加上关键字
override
val name = "sub"
//子类可以定义自己的field和method
val score = "A" def getScore = this.score
}

Scala中override 和 super 关键字

  • Scala中,如果子类要覆盖父类中的一个非抽象方法,必须要使用 override 关键字;子类可以覆盖父类的 val 修饰的field,只要在子类中使用 override 关键字即可。
  • override 关键字可以帮助开发者尽早的发现代码中的错误,比如, override 修饰的父类方法的方法名拼写错误。
  • 此外,在子类覆盖父类方法后,如果在子类中要调用父类中被覆盖的方法,则必须要使用 super 关键字,显示的指出要调用的父类方法。
package com.zy.scala.extends_demo

class Person1 {
private val name = "leo"
val age = 50 def getName = this.name
} class Student extends Person1 {
private val score = "A"
//子类可以覆盖父类的 val field,使用override关键字
override
val age = 30 def getScore = this.score //覆盖父类非抽象方法,必须要使用 override 关键字
//同时调用父类的方法,使用super关键字
override def getName = "your name is " + super.getName
}

Scala中isInstanceOf 和 asInstanceOf

如果实例化了子类的对象,但是将其赋予了父类类型的变量,在后续的过程中,又需要将父类类型的变量转换为子类类型的变量,应该如何做?

  • 首先,需要使用 isInstanceOf 判断对象是否为指定类的对象,如果是的话,则可以使用 asInstanceOf 将对象转换为指定类型;
  • 注意: p.isInstanceOf[XX] 判断 p 是否为 XX 对象的实例;p.asInstanceOf[XX] 把 p 转换成 XX 对象的实例
  • 注意:如果没有用 isInstanceOf 先判断对象是否为指定类的实例,就直接用 asInstanceOf 转换,则可能会抛出异常;
  • 注意:如果对象是 null,则 isInstanceOf 一定返回 false, asInstanceOf 一定返回 null;
  • Scala与Java类型检查和转换

Scala

Java

obj.isInstanceOf[C]

obj instanceof C

obj.asInstanceOf[C]

(C)obj

classOf[C]

C.class

package com.zy.scala.extends_demo

class Person3 {}

class Student3 extends Person3

object Student3 {
def main(args: Array[String]) {
val p: Person3 = new Student3
var s: Student3 = null
//如果对象是 null,则 isInstanceOf 一定返回 false
println(s.isInstanceOf[Student3])
// 判断 p 是否为 Student3 对象的实例
if (p.isInstanceOf[Student3]) {
//把 p 转换成 Student3 对象的实例
s = p.asInstanceOf[Student3]
}
println(s.isInstanceOf[Student3])
}
}

Scala中getClass 和 classOf

  • isInstanceOf 只能判断出对象是否为指定类以及其子类的对象,而不能精确的判断出,对象就是指定类的对象;
  • 如果要求精确地判断出对象就是指定类的对象,那么就只能使用 getClass 和 classOf 了;
  • p.getClass 可以精确地获取对象的类,classOf[XX] 可以精确的获取类,然后使用 == 操作符即可判断;
package com.zy.scala.extends_demo

class Person4 {}

class Student4 extends Person4

object Student4 {
def main(args: Array[String]) {
val p: Person4 = new Student4
//判断p是否为Person4类的实例
println(p.isInstanceOf[Person4]) //true
//判断p的类型是否为Person4类
println(p.getClass == classOf[Person4]) //false
//判断p的类型是否为Student4类
println(p.getClass == classOf[Student4]) //true
}
}

Scala中使用模式匹配进行类型判断

  • 在实际的开发中,比如 spark 源码中,大量的地方使用了模式匹配的语法进行类型的判断,这种方式更加地简洁明了,而且代码的可维护性和可扩展性也非常高;
  • 使用模式匹配,功能性上来说,与 isInstanceOf 的作用一样,主要判断是否为该类或其子类的对象即可,不是精准判断。
  • 等同于 Java 中的 switch case 语法;
package com.zy.scala.extends_demo

class Person5 {}

class Student5 extends Person5

object Student5 {
def main(args: Array[String]) {
val p: Person5 = new Student5
p match {
// 匹配是否为Person类或其子类对象
case per: Person5 => println("This is a Person5's Object!")
// 匹配所有剩余情况
case _ => println("Unknown type!")
}
}
}

Scala中protected

  • 跟 Java 一样,Scala 中同样可使用 protected 关键字来修饰 field 和 method。在子类中,可直接访问父类的 field 和 method,而不需要使用 super 关键字;
  • 还可以使用 protected[this] 关键字, 访问权限的保护范围:只允许在当前子类中访问父类的 field 和 method,不允许通过其他子类对象访问父类的 field 和 method。
package com.zy.scala.extends_demo

class Person6 {
protected var name: String = "tom"
protected[this] var hobby: String = "game" protected def sayBye = println("再见...")
} class Student6 extends Person6 {
//父类使用protected 关键字来修饰 field可以直接访问
def sayHello = println("Hello " + name) //父类使用protected 关键字来修饰method可以直接访问
def sayByeBye = sayBye def makeFriends(s: Student6) = {
println("My hobby is " + hobby + ", your hobby is UnKnown")
}
} object Student6 {
def main(args: Array[String]) {
val s: Student6 = new Student6
s.sayHello
s.makeFriends(s)
s.sayByeBye
}
}

Scala中调用父类的constructor

  • Scala中,每个类都可以有一个主constructor和任意多个辅助constructor,而且每个辅助constructor的第一行都必须调用其他辅助constructor或者主constructor代码;因此子类的辅助constructor是一定不可能直接调用父类的constructor的;
  • 只能在子类的主constructor中调用父类的constructor。
  • 如果父类的构造函数已经定义过的 field,比如name和age,子类再使用时,就不要用 val 或 var 来修饰了,否则会被认为,子类要覆盖父类的field,且要求一定要使用 override 关键字。
package com.zy.scala.extends_demo

class Person7(val name: String, val age: Int) {
var score: Double = 0.0
var address: String = "beijing" def this(name: String, score: Double) = {
//每个辅助constructor的第一行都必须调用其他辅助constructor或者主constructor代码
//主constructor代码
this(name, 30)
this.score = score
} //其他辅助constructor
def this(name: String, address: String) = {
this(name, 100.0)
this.address = address
}
} class Student7(name: String, score: Double) extends Person7(name, score)

Scala中匿名内部类

  • 在Scala中,匿名内部类是非常常见的,而且功能强大。Spark的源码中大量的使用了匿名内部类;
  • 匿名内部类,就是定义一个没有名称的子类,并直接创建其对象,然后将对象的引用赋予一个变量,即匿名内部类的实例化对象。然后将该对象传递给其他函数使用。
package com.zy.scala.extends_demo

class Person8(val name: String) {
def sayHello = "Hello ,I'm " + name
} class GreetDemo {
//接受Person8参数,并规定Person8类只含有一个返回String的sayHello方法
def greeting(p: Person8 {
def sayHello: String}) = {
println(p.sayHello)
}
} object GreetDemo {
def main(args: Array[String]) {
//创建Person8的匿名子类对象
val p = new Person8("tom")
val g = new GreetDemo
g.greeting(p)
}
}

Scala中抽象类

  • 如果在父类中,有某些方法无法立即实现,而需要依赖不同的子类来覆盖,重写实现不同的方法。此时,可以将父类中的这些方法编写成只含有方法签名,不含方法体的形式,这种形式就叫做抽象方法;
  • 一个类中,如果含有一个抽象方法或抽象field,就必须使用abstract将类声明为抽象类,该类是不可以被实例化的;
  • 在子类中覆盖抽象类的抽象方法时,可以不加override关键字;
package com.zy.scala.extends_demo

abstract class Person9(val name: String) {
//必须指出返回类型,不然默认返回为Unit
def sayHello: String def sayBye: String
} class Student9(name: String) extends Person9(name) {
//必须指出返回类型,不然默认
def sayHello: String = "Hello," + name def sayBye: String = "Bye," + name
} object Student9 {
def main(args: Array[String]) {
val s = new Student9("tom")
println(s.sayHello)
println(s.sayBye)
}
}

Scala中抽象field

package com.zy.scala.extends_demo

abstract class Person10 (val name:String){
//抽象fields
val age:Int
}
class Student10(name: String) extends Person10(name) {
val age: Int = 50
}

Scala基础:面向对象之对象和继承的更多相关文章

  1. Java基础-面向对象第二特征之继承(Inheritance)

    Java基础-面向对象第二特征之继承(Inheritance) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.继承的概述 在现实生活中,继承一般指的是子女继承父辈的财产.在程序 ...

  2. Java基础--面向对象编程3(继承)

    1.继承的作用 为了提取两个类中公共的代码,可以使用继承抽取重复性的代码到一个公共类中. 这个公共的类称为父类(super class),继承于父类的类称为子类(sub class). 2.java继 ...

  3. Scala学习之路 (六)Scala的类、对象、继承、特质

    一.类 1.类的定义 scala语言中没有static成员存在,但是scala允许以某种方式去使用static成员这个就是伴生机制,所谓伴生,就是在语言层面上,把static成员和非static成员用 ...

  4. python基础之类与对象,继承与派生

    类与对象 对象的本质也就是一个名称空间而已,用于存放自己独有的属性,而类中存放的是对象共有的属性. __init__会在调用类时自动触发 调用类时发生两件事: 1.创建一个空对象stu1 2.自动触发 ...

  5. 了解JavaScript 面向对象基础 & 原型与对象

    面向对象语言中的对象 老是能听到什么基于对象, 面向对象. 什么是对象, 如果有面向对象基础的人可以无视了, 下面举个简单的例子给大家讲讲面向对象中, 对象的定义, 这个是比较通用的, 不过对于JS来 ...

  6. javascript之面向对象程序设计(对象和继承)

    总结的文章略长,慎点. 知识点预热 引用类型:引用类型的值(对象)是引用类型的一个实例.在ECMAScript中,引用类型是一种数据结构,用于将数据和功能组织在一起.在其他面向对象语言中被称为类,虽然 ...

  7. Scala学习教程笔记二之函数式编程、Object对象、伴生对象、继承、Trait、

    1:Scala之函数式编程学习笔记: :Scala函数式编程学习: 1.1:Scala定义一个简单的类,包含field以及方法,创建类的对象,并且调用其方法: class User { private ...

  8. 第二十七节:Java基础面向对象-静态,单例模式,继承详情知识点

    前言 Java基础面向对象-静态,单例模式,继承详情知识点.静态-static关键字,static变量,静态代码块,代码块(不加静态),对象创建过程,单例模式,继承. 静态-static关键字 // ...

  9. JavaScript 面向对象编程(三):非构造函数对象的继承

    JavaScript 面向对象编程(三):非构造函数对象的继承 一.什么是"非构造函数"的继承? 比如,现在有一个对象,叫做"中国人". var Chinese ...

随机推荐

  1. LeetCode 760. Find Anagram Mappings

    原题链接在这里:https://leetcode.com/problems/find-anagram-mappings/description/ 题目: Given two lists Aand B, ...

  2. 【spring源码学习】spring集成orm数据框架

    [一]简易的数据源配置 (1)配置文件 <!--springJdbcTemplemate数据操作配置信息 --> <bean id="driver" class= ...

  3. 顺丰品牌研究http://www.kiees.cn/sf/express/brand.htm

    顺丰控股股份有限公司,顺丰速运SF,始于1993年,国内速递行业中民族品牌的佼佼者,以其速度快/安全性能高蜚声业界,现已开通海外快递服务,2017年2月完成借壳上市 1993年,顺丰诞生于广东顺德.自 ...

  4. testem方便的web tdd 测试框架使用

    备注:    单元测试,对于日常的开发是比较重要的,testem 简化了我们的代码编写,以及运行.    主要特性:    a. 支持的测试框架有:jasmine quint mocha buster ...

  5. 关于php user ini 文件的配置笔记 (TODO)

    关于 user ini 文件的配置笔记 在使用 宝塔建网站时如果选中防跨域攻击就会在 项目目录生成 .user.ini 这里面是关于 open_basedir 的路径.

  6. Unit04: JSP基本语法 、 JSP运行原理

    Unit04: JSP基本语法 . JSP运行原理 hello.jsp <%@page pageEncoding="utf-8"%> <!doctype html ...

  7. golang的slice作为函数参数传值的坑

    直接贴代码 func sliceModify(slice []int) { // slice[0] = 88 slice = append(slice, ) } func main() { slice ...

  8. CSS 属性单词

    .container {padding:0px; height:90%; width:100%; margin:0;}#header {height:0px; width:100%; padding: ...

  9. .NET实现多个不同有效时间Session方案思考

    什么是Session?简单讲,Session是一种服务端用于保存每个客户端用户的状态信息的机制.客户端第一次访问时,服务端从分配一个空间专门存储该客户端的信息,后续访问时便可以直接获取或者更新状态信息 ...

  10. 【UVa】11882 Biggest Number(dfs+剪枝)

    题目 题目     分析 典型搜索,考虑剪枝. 统计一下联通分量. 1.本位置能够达到所有的点的数量加上本已有的点,还没有之前的结果长,直接返回. 2.当本位置能够达到所有的点的数量加上本已有的点与之 ...