Scala面向对象编程
1. 面向对象编程
1.1 概述
-
Scala是一门完全面向对象的语言,摒弃了Java中很多不是面向对象的语法。虽然如此,但其面向对象思想和Java的面向对象思想还是一致的
class AndroidSys { //定义一个属性 public String company; //定义一个行为方法 public void use() { } } //创建对象 AndroidSys androidObj=new AndroidSys(); androidObj.company="google"; androidObj.use();
1.2 包用法
1.2.1 基本语法
-
Scala中基本的package包语法和Java完全一致
package com.gec.bigdata.scala
1.2.2 scala包的特点
- 可以让源码文件中多次使用package关键字
- 源码物理路径和包名没有关系
- 明确包的作用域,可以在package关键字的后面增加大括号
- 同一个源码中,子包中可以直接访问父包中的内容
- scala可以将包当成对象来用可以直接声明属性和方法
1.2.3 多次使用package
- 多次定义package
package com
package gec
package demo
object Test {
def main(args: Array[String]): Unit = {
println("test main")
}
}
- 嵌套package,体现嵌套层次关系
package com
{
package gec{
package demo{
object Test {
def main(args: Array[String]): Unit = {
println("test main")
}
}
}
}
}
-
同一个源码中,子包中可以直接访问父包中的内容
package com { package gec{ class Test2 { def test2(): Unit = { println("test2...") } } package demo{ object Test { def main(args: Array[String]): Unit = { new Test2().test2(); } } } } }
1.2.4 将package定义成对象
-
定义包对象
- 定义一个包对象,在相同的包里面的资源可以直接访问
- 只要在com.gec.demo的包下的所有的类都可以直接调用testPackageObject方法
package com.gec package object demo { def testPackageObject(): Unit = { println("test package object...") } }
-
使用包对象
package com { package gec{ package demo{ object Test { def main(args: Array[String]): Unit = { testPackageObject() } } } } }
1.3 导入包用法
1.3.1 基本语法
- Scala中基本的import导入语法和Java完全一致
1.3.2 扩展语法
-
星号在scala中有特殊用于,所以不能使用在import语法中,需要采用特殊符号:下划线
import java.util._
-
import关键字可以在任何地方使用
object ScalaImport{ def main(args: Array[String]): Unit = { import java.util.ArrayList new ArrayList() } }
-
Scala中可以导包,而不是导类
object ScalaImport{ def main(args: Array[String]): Unit = { import java.util new util.ArrayList() } }
-
Scala中可以在同一行中导入相同包中的多个类,简化代码
import java.util.{List, ArrayList}
-
隐藏类
import java.util._ import java.sql.{Date=>_, _} new Date() new ArrayList(); new Timestamp(111)
-
Scala中可以给类起别名,简化使用
import java.util.{ArrayList=>AList} object ScalaImport{ def main(args: Array[String]): Unit = { new AList() } }
-
scala中导入类的操作,是以相对路径(当前包路径)的方式导入的。如果想要使用绝对路径的方式,那么需要增加特殊操作:root
println(new _root_.java.util.HashMap()) //package java { // package util { // class HashMap { // // } // } //}
1.4 创建类
1.4.1 概述
- 面向对象编程中类可以看成一个模板,而对象可以看成是根据模板所创建的具体事物
1.4.2 基本语法
// 声明类:访问权限 class 类名 { 类主体内容 }
class User {
// 类的主体内容
}
// 对象:new 类名(参数列表)
new User()
1.4.3 扩展语法
-
scala中的源码可以声明多个类,而且可以声明多个公共类,名称可以和文件名不一样。
package com.gec.scalademo object Scala04_Object_Class { def main(args: Array[String]): Unit = { val test = new Test } class Test { } } class Test2 { } class Test3 { } class Test4 { }
1.5 属性
1.5.1 概述
- 所谓的属性,其实就是类中的变量
1.5.2 特点
-
在编译时,编译器会将变量编译为类的(私有的)属性,同时提供了属性对应的set,get方法
-
val声明的属性,在编译时,会给属性添加final关键字,编译器不会提供属性的set方法
-
scala中变量必须显示地初始化,如果希望类的属性和java一样可以由系统进行初始化,而是手动赋值,可以采用特殊符号:下划线
1.5.2 用法
class Test {
// 声明属性
// private String name = "zhangsan";
// private final int age = 30;
private var name : String = "zhangsan"
val age : Int = 30
@BeanProperty var email : String = _
}
1.6 访问权限
1.6.1 概述
- Scala中的访问权限和Java中的访问权限类似,但是又有区别:
1.6.2 特点
- private => 同类
- private[包名] => 同包,包私有
- protected => 受保护的, 同类,子类,没有同包
- (default) => 什么都不写就是公共的。没有public关键字
1.6.3 用法
class Test6 {
private val name1:String = "zhangsan"
private[scalademo2] var name2:String = "zhangsan"
protected val name3:String = "zhangsan"
val name4:String = "zhangsan"
def test(): Unit = {
println(name1)
println(name2)
println(name3)
println(name4)
}
}
class Test66 {
def test(): Unit = {
val t = new Test6
//println(t.name1)
println(t.name2)
//println(t.name3)
println(t.name4)
}
1.7 方法
1.7.1 概述
- Scala中的类的方法其实就是函数,所以声明方式完全一样,但是必须通过使用对象进行调用
1.7.2 用法
object ScalaMethod{
def main(args: Array[String]): Unit = {
val user = new User
user.login("zhangsan", "000000")
}
}
class User {
def login( name:String, password:String ): Boolean = {
false
}
}
1.8 对象
1.8.1 概述
- Scala中的对象和Java是类似的
1.8.2 用法
val | var 对象名 [:类型] = new 类型()
var user : User = new User()
1.9 构造方法
1.9.1 概述
- 和Java一样,Scala中构造对象也需要调用类的构造方法来创建。并且一个类中可以有任意多个不相同的构造方法。这些构造方法可以分为2大类:主构造函数和辅助构造函数。
- 马丁将构造方法分为2大类 : 主构造方法 & 辅助构造方法
1.9.2 特点
- 用于完成类的初始化操作的构造方法称之为主构造方法
- 其他的构造方法就称之为辅助构造方法, 辅助构造方法的名字是this关键字,其他和普通方法一样
- 辅助构造方法的作用就是在类初始化完成后,做一些辅助功能。
- 辅助构造方法在执行之前,应该首先调用主构造方法完成类的初始化
- 辅助构造方法可以重载的,并且可以互相调用,但是调用的辅助构造方法应该提前声明
1.9.3 定义构造方法
-
和Java一样,Scala中构造对象也需要调用类的构造方法来创建。并且一个类中可以有任意多个不相同的构造方法。这些构造方法可以分为2大类:主构造函数和辅助构造函数。
class User() { // 主构造函数 var username : String = _ def this( name:String ) { // 辅助构造函数,使用this关键字声明 this() // 辅助构造函数应该直接或间接调用主构造函数 username = name } def this( name:String, password:String ) { this(name) // 构造器调用其他另外的构造器,要求被调用构造器必须提前声明 } }
2.0 伴生对象
2.0.1 概述
- scala中没有静态语法,但是可以直接使用java中的静态操作,scala采用了一种特殊的处理方式来代替静态语法 :object,object关键字可以用于创建对象,对象的名字就是声明的名字,使用object关键字声明的类和对象有关系的。这个对象等同于伴随着这个类创建时所产生的,所以将这个对象称之为:伴生对象
2.0.2 作用
- 伴生对象其实就是马丁模拟静态语法所产生的。将静态语法操作的代码写在伴生对象中,将成员方法或属性写在伴生类中
2.0.3 用法
package com.gec.scalademo2
// 伴生类
class Person {
var age:Int=30
}
// 伴生对象
object Person {
def getInstance() : Person = {
new Person()
}
def main(args: Array[String]): Unit = {
val p:Person=getInstance();
}
}
2.1 apply方法
2.1.1 概述
- 如果伴生对象中构建对象的方法名成为apply,编译器可以自动识别的,所以这个方法名可以省略的
2.1.2 用法
package com.gec.scalademo
object Scala09_Object_Instance_5 {
def main(args: Array[String]): Unit = {
// 如果伴生对象中构建对象的方法名成为apply,编译器可以自动识别的,所以这个方法名可以省略的
val test1: Test = Test.apply()
val test2 = new Test() // 调用类的构造方法
val test3 = Test() // 调用的是伴生对象的apply方法
val test4 = Test // 伴生对象本体
}
class Test() {
println("ttttt")
}
object Test {
def apply() = {
println("apply")
new Test()
}
}
}
2. 高阶面向对象编程
2.1 继承
2.1.1 概述
- 和Java一样,Scala中的继承也是单继承,且使用extends关键字。
2.1.2 用法
class Person {
}
class User extends Person {
}
2.2 封装
2.2.1 概述
- 封装就是把抽象出的数据和对数据的操作封装在一起,数据被保护在内部,程序的其它部分只有通过被授权的操作(成员方法),才能对数据进行访问。
2.2.2 作用
-
将属性进行私有化
-
提供一个公共的set方法,用于对属性赋值
-
提供一个公共的get方法,用于获取属性的值
2.3 抽象
2.3.1 概述
-
Scala将一个不完整的类称之为抽象类。
abstract class Person { }
2.3.1 定义抽象方法
-
Scala中如果一个方法只有声明而没有实现,那么是抽象方法,因为它不完整。
abstract class Person { def test():Unit }
2.3.2 定义抽象属性
-
Scala中如果一个属性只有声明没有初始化,那么是抽象属性,因为它不完整。
abstract class Person { var name:String }
2.3.3 子类继承父类
-
子类如果继承抽象类,必须实现抽象方法或补全抽象属性,否则也必须声明为抽象的,因为依然不完整。
abstract class Person { var name:String } class User extends Person { var name : String = "zhangsan" }
2.4 特质
2.4.1 概述
- Scala将多个类的相同特征从类中剥离出来,形成一个独立的语法结构,称之为“特质”(特征)。这种方式在Java中称之为接口,但是Scala中没有接口的概念。所以scala中没有interface关键字,而是采用特殊的关键字trait来声明特质, 如果一个类符合某一个特征(特质),那么就可以将这个特征(特质)“混入”到类中。这种混入的操作可以在声明类时使用,也可以在创建类对象时动态使用。
2.4.2 基本语法
trait 特质名称
class 类名 extends 父类(特质1) with 特质2 with特质3
trait Operator {
}
trait DB{
}
class MySQL extends Operator with DB{
}
2.4.3 动态混入
-
概述
-
动态混入是 Scala 特有的方式 (java 没有动态混入),可在不修改类声明/定义的情况下,扩展类的功能,非常的灵活,耦合性低 。
-
用法
object ScalaTrait{ def main(args: Array[String]): Unit = { val mysql = new MySQL with Operator mysql.insert() } } trait Operator { def insert(): Unit = { println("insert data...") } } class MySQL { }
2.4.4 特质是抽象类与接口混合体
-
概述
-
可以将trait理解为接口和抽象类的结合体
-
用法
package com.gec.bigdata.scala.chapter06 object Scala12_Object_Trait_2 { def main(args: Array[String]): Unit = { // TODO 面向对象 - 特征(特质) // 可以将trait理解为接口和抽象类的结合体 new User() } trait Test extends Exception { def test(): Unit } class Person{ } class User extends Test { override def test(): Unit = { } } }
2.4.5 初始化问题
-
概述
-
初始化问题
父类的特质 > 父类 > 特质1, 特质2 > 当前类
-
-
用法
package com.gec.bigdata.scala.chapter06 object Scala12_Object_Trait_3 { def main(args: Array[String]): Unit = { // TODO 面向对象 - 特征(特质) // 1. 初始化问题 // 父类的特质 > 父类 > 特质1, 特质2 > 当前类 //new User() } trait Test extends Test1{ println("aaaa") } trait Test1 { println("dddd") } class Person{ println("bbbb") } class User extends Person with Test with Test1 { println("cccc") } }
2.4.6 功能叠加
-
概述
-
scala采用了一种功能叠加的方式解决砖石问题,super不是父特质的意思,是上一级(上一个)的意思
-
用法
package com.gec.bigdata.scala.chapter06 object Scala12_Object_Trait_4 { def main(args: Array[String]): Unit = { // TODO 面向对象 - 特征(特质) // java中不能类的多继承 : 砖石问题 // scala采用了一种功能叠加的方式解决砖石问题 // super不是父特质的意思,是上一级(上一个)的意思 new MySQL().operData() } trait Operator { def operData(): Unit = { println("操作数据") } } trait DB extends Operator{ override def operData(): Unit = { print("向数据库中") super.operData() } } trait Log extends Operator { override def operData(): Unit = { print("向日志文件中") super[Operator].operData() } } class MySQL extends DB with Log { } }