一、封装
定义一个类,实际上就是把一类事物的共有的属性和行为提取出来,形成一个物理模型(模板)。这种研究问题的方法称为抽象。
面向对象编程有三大特征:封装、继承和多态。
封装(encapsulation)就是把抽象出的数据和对数据的操作封装在一起, 数据被保护在内部,程序的其它部分只有通过被授权的操作(成员方法),才能对数据进行操作。
封装的理解和好处:
隐藏实现细节,可以对数据进行验证,保证安全合理
如何体现封装:
对类中的属性进行封装
通过成员方法,包实现封装
封装的实现步骤将属性进行私有化提供一一个公 共的set方法,用于对属性判断并赋值
提供一个公共的get方法,用于获取属性的值
封装的示例代码:
package encapsulationDemo /** * @author : 蔡政洁 * @email :caizhengjie888@icloud.com * @date : 2020/9/17 * @time : 10:57 下午 * scala的类的定义 * Scala和Java一样,都是用关键字class来进行声明 * 在Scala中刚刚创建的这个类,其实就模拟了Java中的javabean,当然在Scala中有一个专门的类结构来表示Java中的bean -- case class(样例类), * 会自动的给其中的字段提供getter和setter方法 */ object ClassOps { def main(args: Array[String]): Unit = { // 创建类的对象 val person:Person = new Person() person.setName("张三") person.setAge(14) println(s"name:${person.getName},age:${person.getAge}") } } // 定义了一个Scala的类,类名为Person class Person{ // 定义了一个String类型的成员name,并赋予默认值,默认值为null private var name:String = _ // 定义了一个Int类型的成员age,并赋予默认值,默认值为0 private var age:Int = _ // 提供getter和setter来处理 def setName(n:String):Unit = { name = n } // 单行函数 def getName = name def setAge(a:Int):Unit = { if (a<1 || a>=150){ throw new RuntimeException("年龄不能小于1,或者不能超过150岁") } age = a } def getAge = age }
运行结果:
name:张三,age:14
二、类的构造
1、和Java或C++一样,Scala可以有任意多的构造器。不过Scala类有一个构造器比其他所有构造器都更为重要,它就是主构造器(primary constructor) 。除了主构造器之外,类还可以有任意多的辅助构造器( auxiliary constructor)
2、辅助构造器的名称为this。在Java或C++中,构造器的名称和类名相同,当你修改类名时就不那么方便了。每一个辅助构造器都必须以一个对先前已定义的其他辅助构造器或主构造器的调用开始
3、scala中构造器的定义
(1)Scala中和类名相同的方法并不是构造器
(2)通过分析,Scala的其中一个构造器就在类名后面,因为是无参的,所以默认省略(),也是参数列表
问题分析:
1、该构造器的方法体呢?
通过代码验证,说明Scala类的构造器的函数体和类的定义交织在了一起
2、可不可以拥有其他的构造器?
Scala不能用类名做构造器,而是使用this关键字来代替这里的类名
(3)由2的内容,我们可以归纳如下
Scala的构造器有两种,一种在类名后面定义的,一种在类中使用关键字来定义的
第一种的构造器,被称为Scala类的主构造器
第二种的构造器,被称为Scala类的辅助构造器
Scala中的辅助构造器的第一句话,必须要调用本类的主构造器或者其他辅助构造器
类的构造示例代码:
package encapsulationDemo /** * @author : 蔡政洁 * @email :caizhengjie888@icloud.com * @date : 2020/9/18 * @time : 1:37 下午 * scala中构造器的定义 * 1、Scala中和类名相同的方法并不是构造器 * 2、通过分析,Scala的其中一个构造器就在类名后面,因为是无参的,所以默认省略(),也是参数列表 * 问题分析? * 1、该构造器的方法体呢? * 通过代码验证,说明Scala类的构造器的函数体和类的定义交织在了一起 * 2、可不可以拥有其他的构造器? * Scala不能用类名做构造器,而是使用this关键字来代替这里的类名 * 3、由2的内容,我们可以归纳如下 * 1、Scala的构造器有两种,一种在类名后面定义的,一种在类中使用关键字来定义的 * 第一种的构造器,被称为Scala类的主构造器 * 第二种的构造器,被称为Scala类的辅助构造器 * 2、Scala中的辅助构造器的第一句话,必须要调用本类的主构造器或者其他辅助构造器 */ object ConstructorOps { def main(args: Array[String]): Unit = { val teacher:Teacher = new Teacher() teacher.show() teacher.Teacher() println("==========这里使用Scala的有参数的构造器==========") val teacher1 = new Teacher("李四",20) teacher1.show() println("==========这里使用Scala的有参主构造器==========") val teacher2 = new Teacher1("张三",23) teacher2.show() } } // Scala中有参主构造器 class Teacher1/*private主构造器的私有化*/ (name:String,age:Int){ def show():Unit = { println(s"name:${name},age:${age}") } } class Teacher(/*这是Scala的默认的类的无参构造器,而且这还是最特殊的一个构造器*/){ private var name:String = _ private var age:Int = _ println("如果这是类的构造器的话,该语句将会被调用~") // Scala中Teacher()不是构造器,就是普通方法 def Teacher():Unit = { println("如果这是类的构造器的话,该方法将会被调用~") } def this(name:String,age:Int){ this() this.name = name this.age = age println("如果这是类的有参构造器的话,该语句将会被调用") } def show():Unit = { println(s"name:${name},age:${age}") } }
运行结果:
如果这是类的构造器的话,该语句将会被调用~ name:null,age:0 如果这是类的构造器的话,该方法将会被调用~ ==========这里使用Scala的有参数的构造器========== 如果这是类的构造器的话,该语句将会被调用~ 如果这是类的有参构造器的话,该语句将会被调用 name:李四,age:20 ==========这里使用Scala的有参主构造器========== name:张三,age:23
三、内部类
示例代码:
package encapsulationDemo /** * @author : 蔡政洁 * @email :caizhengjie888@icloud.com * @date : 2020/9/18 * @time : 2:30 下午 * Scala内部类 */ object InnerClassOps { def main(args: Array[String]): Unit = { val outer:Outer = new Outer() // 创建Scala的内部类对象 val inner = new outer.Inner() inner.show() } } class Outer { o => // 此时o就是本类对象的引用 val x = 5 class Inner{ i => // 此时就是本类对象的引用 val x = 6 def show(): Unit ={ val x = 7 println("x = "+x) println("x = "+this.x) println("x = "+i.x) println("x = "+Outer.this.x) println("x = "+o.x) } } }
运行结果:
x = 7 x = 6 x = 6 x = 5 x = 5
四、Object对象
scala中的Object结构:
在Java的一个类中,既可以拥有static静态,也可以拥有非static,同时Java中的主函数必须是static。但是Scala中的class只能提供非static的成员,所以要想Scala也能提供static的成员,就必须使用object结构。Scala的object中定义的成员都是类似于Java中的静态成员,也就是直接可以通过类名.调用,无需创建对象。
object的主要作用:
给Scala类提供程序运行入口,静态的main函数
给Scala类也能够提供静态成员–Scala类的伴生对象来实现
object ObjectOps { def main(args: Array[String]): Unit = { println("hello world") } }
五、伴生对象
scala中的伴生对象:scala中把同一个源文件中相同名称的object结构称为class结构的伴生对象,反过来把这个class结构称之为object结构的伴生类。
class CompanionClass 是object CompanionClass的伴生类
object CompanionClass 是 class CompanionClass的伴生对象
构建伴生类/伴生对象成立的几个前提:
1、二者必须在同一个.class源文件
2、二者名称必须相同
伴生类/伴生对象的特点:
1、伴生对象可以访问伴生类中非私有和私有的成员
2、通常我们需要在伴生对象中覆盖一个方法–apply,用于构造伴生类的实例
比如,Array,ArrayBuffer,Map 等等都是通过伴生对象来创建对象,该构造的时候其实就是调用了伴生对象apply方法。该apply方法的特点:
返回值类型是本类引用
参数列表对应伴生类的构造器的参数列表
3、有了伴生对象,同时覆盖了apply方法,便给伴生类提供了一个简化的对象构造器方式,即省略了new关键字
代码示例:
package encapsulationDemo /** * @author : 蔡政洁 * @email :caizhengjie888@icloud.com * @date : 2020/9/21 * @time : 9:48 上午 * * scala中的伴生对象 * scala中把同一个源文件中相同名称的object结构称为class结构的伴生对象,反过来把这个class结构称之为 * object结构的伴生类。 * * class CompanionClass 是object CompanionClass的伴生类 * object CompanionClass 是 class CompanionClass的伴生对象 * 构建伴生类/伴生对象成立的几个前提 * 1、二者必须在同一个.class源文件 * 2、二者名称必须相同 * 伴生类/伴生对象的特点 * 1、伴生对象可以访问伴生类中非私有和私有的成员 * 2、通常我们需要在伴生对象中覆盖一个方法--apply,用于构造伴生类的实例 * 比如,Array,ArrayBuffer,Map 等等都是通过伴生对象来创建对象,该构造的时候其实就是调用了伴生对象apply方法 * 该apply方法的特点: * 1、返回值类型是本类引用 * 2、参数列表对应伴生类的构造器的参数列表 * 3、有了伴生对象,同时覆盖了apply方法,便给伴生类提供了一个简化的对象构造器方式,即省略了new关键字 * */ object CompanionObjectOps { def main(args: Array[String]): Unit = { val cc = new CompanionClass() println("-------------------") val cc1 = CompanionClass println("-------------------") val cc2 = CompanionClass("张三",13) } } class CompanionClass{ private val x = 6 def this(name:String,age:Int){ this() println("name:"+name) println("age:"+age) } } object CompanionClass{ val cc = new CompanionClass println(cc.x) def apply(): CompanionClass = { new CompanionClass() } def apply(name:String,age:Int): CompanionClass = { new CompanionClass(name,age) } }
运行结果:
------------------- 6 ------------------- name:张三 age:13
六、类的继承
Scala扩展类的方式和Java一样,使用extends关键字:
继承就代表,子类可以从父类继承父类的field和method,然后子类可以在自己内部放入父类所没有,子类特有的field和method,使用继承可以有效复用代码。
不可扩展关键字:
子类可以覆盖父类的field和method,但是如果父类用final修饰,field和method用finaI修饰, 则该类是无法被扩展的,field和method是无法被覆盖的。
scala 中的继承/扩展
使用关键字extends来产生这种继承或者扩展关系
子类可以继承父类中所有非私有的成员
子类不能覆盖父类中被final所修饰的成员
Scala中子类覆盖父类的方法时,必须要添加关键字override进行修饰,以标识要对父类方法进行覆盖,否则认为子类重新定义一个同名方法,这就会造成方法同名,会报错
子类要想访问父类的成员时候,就需要使用super关键字来完成
示例代码:
package extendsDemo /** * @author : 蔡政洁 * @email :caizhengjie888@icloud.com * @date : 2020/9/22 * @time : 2:53 下午 * * scala 中的继承/扩展 * 1、使用关键字extends来产生这种继承或者扩展关系 * 2、子类可以继承父类中所有非私有的成员 * 3、子类不能覆盖父类中被final所修饰的成员 * 4、Scala中子类覆盖父类的方法时,必须要添加关键字override进行修饰,以标识要对父类方法进行覆盖, * 否则认为子类重新定义一个同名方法,这就会造成方法同名,会报错 * 5、子类要想访问父类的成员时候,就需要使用super关键字来完成 */ object ExtendsOps1 { def main(args: Array[String]): Unit = { val stu = new Student("张三") stu.show() } } // 父类 class Person{ var name:String = _ var age:Int = 15 def this(name:String,age:Int){ this() this.name = name this.age = age } def show(): Unit ={ println(s"name:${name},age:${age}") } def setName(name:String) = this.name = name } // 子类 class Student extends Person{ def this(name:String){ this() // 完成name的赋值 // this.name = name super.setName(name) } override def show(): Unit = { // 调用父类的show方法 super.show() println("------student-----show------") } }
运行结果:
name:张三,age:15 ------student-----show------