三, 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")
        }
    }
}
 
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号