三, Scala 面向对象基础知识汇总

六, Scala 中的面向对象

  • Scala 的面向对象思想,概念与Java 的基本一致, 但是语法和Java不同, 补充了更多的功能;

6.1 包

  • 基本语法 package 包名
  • Scala包的三大作用(和Java一样)
    1. 区分同名类
    2. 在类很多的时候, 很好的管理类
    3. 控制访问的范围

6.1.1 包的命名

  • 数字, 字母, 下划线, 小圆点
    在这里插入图片描述

6.1.2 包说明语句

[说明]

  • Scala有两种包的管理风格,
  1. 第一种和Java 的包管理风格相同, 每个源文件一个包(包名和源文件所在路径不要求一致), 包名用"."进行分隔以表示包的层级关系, 如 org.apache.scala
  2. 第二种风格, 通过嵌套的风格表示层级关系, 如下所示; 这种风格的特点是: 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 类的定义

  • 类: 模板;
  • 对象: 具体的事物;

类的定义:

  1. Java中, 一个.java文件中一定有一个public类, 这个类名与.java文件名还相同;
  2. 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中类的访问权限:
    1. Scala中属性和方法的默认访问权限为public, 但Scala中无public关键字;
    2. private[包名], 包访问权限, 包内, 相当于Java的default;
    3. protect为受保护权限,同类, 子类可访问,同包无法访问, 比Java的default还要严格一些;
    4. private为私有权限, 只在类的内部和伴生对象中使用;

6.3.2 方法

[基本语法]

def 方法名(参数列表) [:返回值类型] = {
    方法体
}

在这里插入图片描述

6.3.3 创建对象

[基本语法]

val | var 对象名 [: 类型] = new 类型()

[案例]
在这里插入图片描述

6.3.4 构造器

和Java一样, Scala构造对象也需要调用构造方法, 并且可以有任意多个构造方法;

  • Scala的构造器包括: 主构造器辅构造器;

[基本语法]

// 可以看到Scala的构造器声明就是在class 类名后面传入一些参数即可;
class 类名(形参列表){
    //类体
    def this(形参列表){ //辅助构造器
    }

    def this(形参列表){//辅助构造器
    }
}

说明:

  1. 辅助构造器, 函数名称均为this, 可以有多个, 编译器通过参数的个数及类型来区分;
  2. 辅助构造器不能直接构建对象, 必修直接或者间接调用主构造方法;
  3. 辅助构造器调用其他另外的构造器, 要求被调用构造必须提前声明;
//(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 父类名{
    类体
}
  1. 子类继承父类的属性和方法
  2. Scala是单继承
  3. 继承的调用顺序, 从父类构造器-> 子类构造器

[案例]

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中只有一般方法为动态绑定;

[多态案例]

  1. 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();
    }
}
  1. 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")
        }
    }
}
posted @   青松城  阅读(51)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示