三, Scala 面向对象基础知识汇总
六, Scala 中的面向对象
- Scala 的面向对象思想,概念与Java 的基本一致, 但是语法和Java不同, 补充了更多的功能;
6.1 包
- 基本语法 package 包名
- Scala包的三大作用(和Java一样)
- 区分同名类
- 在类很多的时候, 很好的管理类
- 控制访问的范围
6.1.1 包的命名
- 数字, 字母, 下划线, 小圆点
6.1.2 包说明语句
[说明]
- Scala有两种包的管理风格,
- 第一种和Java 的包管理风格相同,
每个源文件一个包(包名和源文件所在路径不要求一致), 包名用"."进行分隔以表示包的层级关系
, 如 org.apache.scala - 第二种风格,
通过嵌套的风格表示层级关系
, 如下所示; 这种风格的特点是:1. 一个源文件中可以声明多个package; 2. 子包中的类可以直接访问父包中的内容, 无需导包;
第二种风格:
1.一个源文件可以声明多个包; 2. 子包中的类可以直接访问父包的内容, 无需导包
package org{
pakage apache{
pakage scala{
}
}
}
6.1.2 包对象
- 在Scala中可以为每个包定义一个
与包同名的包对象
, - 定义在
包对象中的成员, 是包对象对应的包下所有class和object的共享变量, 可以被直接访问
6.1.3 导包说明
6.2 类和对象
6.2.1 类的定义
- 类: 模板;
- 对象: 具体的事物;
类的定义:
- Java中, 一个.java文件中一定有一个public类, 这个类名与.java文件名还相同;
- Scala中, 所有的类默认都是public修饰, 一个Scala源文件可以包含多个类;
6.2.2 类的属性
属性是类的一个组成部分
[属性定义语法]
[修饰符] var|val 属性名称 [:类型] = 属性值
比如: var name: String = “sb”
注意:
@BeanProperty
可以对属性自动生成规范的 getXX和 SetXX方法
- 举个栗子:
6.3 封装
- 把抽象出的数据和对数据的操作封装在一起;
6.3.1 访问权限
- Java中类的访问权限: ( public(全部可见) -> protect(包内和不同包的子类) -> default(包内) -> private(类内) )
- Scala中类的访问权限:
- Scala中属性和方法的默认访问权限为public, 但Scala中无public关键字;
- private[包名], 包访问权限,
包内
, 相当于Java的default; - protect为受保护权限,
同类, 子类可访问,同包无法访问
, 比Java的default还要严格一些; - private为私有权限, 只在
类的内部和伴生对象
中使用;
6.3.2 方法
[基本语法]
def 方法名(参数列表) [:返回值类型] = {
方法体
}
6.3.3 创建对象
[基本语法]
val | var 对象名 [: 类型] = new 类型()
[案例]
6.3.4 构造器
和Java一样, Scala构造对象也需要调用构造方法, 并且可以有任意多个构造方法;
- Scala的构造器包括: 主构造器和辅构造器;
[基本语法]
// 可以看到Scala的构造器声明就是在class 类名后面传入一些参数即可;
class 类名(形参列表){
//类体
def this(形参列表){ //辅助构造器
}
def this(形参列表){//辅助构造器
}
}
说明:
- 辅助构造器, 函数名称均为this, 可以有多个, 编译器通过参数的个数及类型来区分;
辅助构造器不能直接构建对象, 必修直接或者间接调用主构造方法
;- 辅助构造器调用其他另外的构造器, 要求
被调用构造必须提前声明
;
//(1)如果主构造器无参数,小括号可省略
//class Person (){
class Person {
var name: String = _
var age: Int = _
//带参的辅助构造方法1
def this(age: Int) {
this()
this.age = age
println("辅助构造器")
}
//带参的辅助构造方法2
def this(age: Int, name: String) {
this(age)
this.name = name
}
println("主构造器")
}
object Person {
def main(args: Array[String]): Unit = {
val person2 = new Person(18)
}
}
6.3.4 构造器参数
class Person(name: String, var age: Int, val sex: String) {
}
object Test {
def main(args: Array[String]): Unit = {
var person = new Person("bobo", 18, "男")
// (1)未用任何修饰符修饰,这个参数就是一个局部变量
// printf(person.name)
// (2)var 修饰参数,作为类的成员属性使用,可以修改
person.age = 19
println(person.age)
// (3)val 修饰参数,作为类的只读属性使用,不能修改
// person.sex = "女"
println(person.sex)
}
}
6.4 继承和多态
[基本语法]
class 子类名 extends 父类名{
类体
}
- 子类继承父类的属性和方法
- Scala是单继承
- 继承的调用顺序, 从父类构造器-> 子类构造器
[案例]
class Person(nameParam: String) {
var name = nameParam
var age: Int = _
def this(nameParam: String, ageParam: Int) {
this(nameParam)
this.age = ageParam
println("父类辅助构造器")
}
println("父类主构造器")
}
class Emp(nameParam: String, ageParam: Int) extends Person(nameParam, ageParam) {
var empNo: Int = _
def this(nameParam: String, ageParam: Int, empNoParam: Int) {
this(nameParam, ageParam)
this.empNo = empNoParam
println("子类的辅助构造器")
}
6.4.1 多态和动态绑定
- 什么多态: 对于同一方法, 由于对象的不同可能会有不同的行为, 这种形式叫多态(具体来说是运行是多态);
- 关于多态的具体阐述, 请参阅此文: Java面向对象, 第三节
什么是动态绑定?
- 文章1: 关于多态以及动态绑定
- 文章2
- 文章3
- 绑定: 一个具体的方法和该方法所属的具体类进行关联; 即, 在执行方法调用时, jvm知道该调用哪个类的实现方法;
- 静态绑定(编译和运行都看左边):
- 程序在执行前就知道了该方法所属的类(
编译前该方法已经绑定
) , Java中, 只有private, static, final修饰的方法以及 构造方法, 还有所有的变量都是静态绑定;
- 程序在执行前就知道了该方法所属的类(
- 动态绑定(编译看左边, 执行看右边):
- 程序运行时根据对象的类型(所属的类)进行绑定, Java中的一般方法是动态绑定, 动态绑定是实现多态的基础;
Scala中属性和方法都是动态绑定, 而Java中只有一般方法为动态绑定;
[多态案例]
- Java的多态
public class PolymorphicOfJava {
//父类
static class Person{
String name = "person";
int age = 0;
public void sayHi(){
System.out.println("hell0, i am a person, name: "+ name + "age: " + age);
}
}
//子类
static class Student extends Person{
String name = "student";
int age = 18;
@Override
public void sayHi() {
System.out.println("hell0, i am a person, name: "+ name + "age: " + age);
}
public void byeBye(){
System.out.println(" bye, bye");
}
}
public static void main(String[] args) {
//1. 直接使用父类创建对象, 此时jvm皆是通过父类引用调用父类属性和方法
Person person = new Person();
//1.1 访问成员变量
System.out.println(person.name + ":" + person.age);
/1.2 访问成员方法
person.sayHi();
System.out.println("==========================");
//2. 向下转型, 父类引用指向子类对象, 此时就涉及到java中的静态和动态绑定问题
静态绑定(所有的变量, static,final, private方法, 构造方法), 编译和运行均看左边类
/// 动态绑定(一般方法), 编译看左边(先看左边的类有没有), 运行看右边(再去右边的类去调用)
Person student = new Student();
/1.1 访问成员变量, 注意了, 这里是静态绑定(编译和运行都看左边的类, 所以会调用左边的类也就是Person父类的成员变量, perosn: 0)
System.out.println(student.name + ":" + student.age);
1.2 访问成员方法(遵循动态绑定, 所以编译看左边(父类有没有这个方法), 执行看右边(再去子类执行这个方法))
student.sayHi();
//由于一般方法遵循动态绑定, 所以编译看左边(父类有没有这个方法), 执行看右边(再去子类执行这个方法), 父类没有byeBye(),
// 所以这一句会直接报错, 编译阶段都过不去
//student.byeBye();
}
}
- Scala的多态
object Polymophic {
def main(args: Array[String]) = {
var person: Person = new Person();
person.sayHi()
println("============================")
//多态, 父类引用指向子类对象
var student: Person = new Student();
student.sayHi()
}
}
//1.父类
class Person{
//成员变量
val name: String = "Person"
val age: Int = 0
//访问成员变量
println(s"${name}:${age}")
println("我是父类的一个普通方法")
//成员方法
def sayHi(): Unit = {
println(s"hello, i am person, name: ${name}, age: ${age}")
}
}
//2. 子类
class Student extends Person{
//重写继承来的成员变量
//注意: var不能被重写
override val name: String = "Student"
override val age: Int = 18
println(s"${name}:${age}")
println("我是子类的一个普通方法")
//重写继承来的方法
override def sayHi(): Unit = {
println(s"hello, i am student, name: ${name}, age: ${age}")
}
}
Q: 为什么子类调用方法时, 父类方法也被执行了>? ???
6.6 抽象类
6.6.1 抽象属性和抽象方法
[基本语法]
//1. 定义抽象类
通过abstract关键字标记抽象类
abstract class Person{}
//2. 定义抽象属性
一个属性没有初始化, 就是抽象属性
val|var name: String
//3. 定义抽象方法
只声明而没有实现的方法, 就是抽象方法
def hello(): String
[案例实操]
abstract class Person {
val name: String
def hello(): Unit
}
class Teacher extends Person {
val name: String = "teacher"
def hello(): Unit = {
println("hello teacher")
}
}
6.6.2 继承和重写
6.6.3 匿名子类
和 Java 一样,可以通过包含带有定义或重写的代码块的方式创建一个匿名的子类。
[案例]
abstract class Person {
val name: String
def hello(): Unit
}
object Test {
def main(args: Array[String]): Unit = {
val person = new Person {
override val name: String = "teacher"
override def hello(): Unit = println("hello teacher")
}
}
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战