【Scala】面对对象

本文介绍了Scala中的包管理,包括命名规范和包的组织结构。详细讲解了类的定义、属性和方法,以及构造器和构造器参数。还探讨了继承、多态和动态绑定的概念。特质作为Scala中的一个重要特性,允许类实现多重行为。此外,文章还提到了单例对象(伴生对象)的应用和apply方法的作用。
摘要由CSDN通过智能技术生成

目录

​​​​​​​包

命名

包说明(包语句)

 Java 的包管理风格

嵌套的风格

(1)使用 Java 的包管理风格

(2)采用嵌套方式管理包

导包

Scala 中的三个默认导入分别是

基本

属性

访问权限

方法

创建对象

构造器

构造器参数

继承和多态

动态绑定

抽象类 ​​​​​​​

继承&重写

匿名子类

难点

单例对象(伴生对象)

apply 方法

特质(Trait)

特质叠加

特质自身类型

特质和抽象类的区别

其他

类型检查和转换

枚举类和应用类

Type 定义新类型

来源


​​​​​​​

package 包名
1 )区分相同名字的类
2 )当类很多时,可以很好的管理类
3 )控制访问范围

命名

只能包含数字、字母、下划线、小圆点 . ,但不能用数字开头,也不要使用关键字。
规范
一般是小写字母 + 小圆点
com. 公司名 . 项目名 . 业务模块名 ​​

包说明(包语句)

 Java 的包管理风格

每个源文件一个包(包 名和源文件所在路径不要求必须一致),包名用“.”进行分隔以表示包的层级关系,如 com.atguigu.scala。

嵌套的风格

package com{
    package atguigu{
        package scala{
        }
    }
}
1 )一个源文件中可以声明多个 package
2 )子包中的类可以直接访问父包中的内容,而无需导包
包对象 ​​​​​​​
Scala 中可以为每个包定义一个 同名 的包对象,定义在包对象中的成员,作为其
应包下 所有 class object 的共享变量,可以被直接访问
package object com{
    val shareValue="share"
    def shareMethod()={}
}

1)使用 Java 的包管理风格

包对象一般定义在其对应包下的 package.scala 文件中,包对象名与包名保持一致。

2)采用嵌套方式管理包

包对象可与包定义在同一文件中,但是要保证包对象 与包声明在同一作用域中
package com {
 object Outer {
 val out: String = "out"
 def main(args: Array[String]): Unit = {
 println(name)
 }
 }
}
package object com {
 val name: String = "com"
}

导包

1 )和 Java 一样,可以在顶部使用 import 导入,在这个文件中的所有类都可以使用。
2 )局部导入:什么时候使用,什么时候导入。 在其作用范围内都可以使用
3 )通配符导入: import java.util._
4 )给类起名: import java.util.{ArrayList=>JL}
5 )导入 相同包的 多个类: import java.util.{HashSet, ArrayList}
6 )屏蔽类: import java.util.{ArrayList =>_,_}
7 )导入包的绝对路径: new _root_.java.util.HashMap
package java {
 package util {
 class HashMap {
 }
 }
}

Scala 中的三个默认导入分别是

import java.lang._
import scala._
import scala.Predef._

Scala 中没有 public ,一个 .scala 中可以写多个类。  
[修饰符] class 类名 {
 类体
}
1 Scala 语法中,类并不声明为 public ,所有这些类都具有公有可见性(即默认就是
public
2 )一个 Scala 源文件可以包含多个类

基本

属性

[修饰符] var|val 属性名称 [:类型] = 属性值
import scala.beans.BeanProperty
class Person {
 var name: String = "bobo" //定义属性
 var age: Int = _ // _表示给属性一个默认值
 //Bean 属性(@BeanProperty)
 @BeanProperty var sex: String = "男"
//val 修饰的属性不能赋默认值,必须显示指定
}
object Person {
 def main(args: Array[String]): Unit = {
 var person = new Person()
 println(person.name)
 person.setSex("女")
 println(person.getSex)
 }
}
Bean 属性( @BeanPropetry ),可以自动生成规范的 setXxx/getXxx 方法
Scala 中的 public 属性,底层实际为 private ,并通过 get 方法( obj. field() )和 set 方法
obj. field_=(value) )对其进行操作。所以 Scala 并不推荐将属性设为 private ,再为其设置
public get set 方法的做法。但由于很多 Java 框架都利用反射调用 getXXX setXXX
法,有时候为了和这些框架兼容,也会为 Scala 的属性设置 getXXX setXXX 方法(通过
@BeanProperty 注解实现)。
属性=_ 默认为空值

访问权限

1 Scala 中属性和方法的默认访问权限为 public ,但 Scala 中无 public 关键字。
2 private 为私有权限,只在类的内部和伴生对象中可用。
3 protected 为受保护权限, Scala 中受保护权限比 Java 中更严格,同类、子类可以
访问,同包无法访问。
4 private[ 包名 ] 增加包访问权限,包名下的其他类也可以使用

方法

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

创建对象

val | var 对象名 [:类型] = new 类型()
1 val 修饰对象,不能改变对象的引用(即:内存地址),可以改变对象属性的值。
2 var 修饰对象,可以修改对象的引用和修改对象的属性值
3 )自动推导变量类型不能多态,所以多态需要显示声明​​​​​​​
class Person {
 var name: String = "canglaoshi"
}
object Person {
 def main(args: Array[String]): Unit = {
 //val 修饰对象,不能改变对象的引用(即:内存地址),可以改变对象属性的值。
 val person = new Person()
 person.name = "bobo"
 // person = new Person()// 错误的
 println(person.name)
 }
}

构造器

Java 一样, Scala 构造对象也需要调用构造方法,并且可以有任意多个构造方法。
Scala 类的构造器包括: 主构造器和辅助构造器
class 类名(形参列表) { // 主构造器
 // 类体
 def this(形参列表) { // 辅助构造器
 }
 def this(形参列表) { //辅助构造器可以有多个...
 }
}
1 )辅助构造器,函数的名称 this ,可以有多个,编译器通过参数的个数及类型
来区分。
2 )辅助构造方法不能直接构建对象,必须直接或者间接调用主构造方法。
3 )构造器调用其他另外的构造器,要求被调用构造器必须提前声明。
//(1)如果主构造器无参数,小括号可省略
//class Person (){
class Person {
 var name: String = _
 var age: Int = _
 def this(age: Int) {
this()
 this.age = age
 println("辅助构造器")
 }
 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)
 }
}

构造器参数

Scala 类的主构造器函数的形参包括三种类型:未用任何修饰、 var 修饰、 val 修饰
1 )未用任何修饰符修饰,这个参数就是一个局部变量
2 var 修饰参数,作为类的成员属性使用,可以修改
3 val 修饰参数,作为类只读属性使用,不能修改
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)
 }
}

继承和多态

class 子类名 extends 父类名 { 类体 }
1 )子类继承父类的 属性 方法
2 scala 是单继承

动态绑定

Scala 中属性和方法都是动态绑定,而 Java 中只有方法为动态绑定。 ​​​​​​​

抽象类 ​​​​​​​

1 )定义抽象类: abstract class Person{} // 通过 abstract 关键字标记抽象类
2 )定义抽象属性: val|var name:String // 一个属性没有初始化,就是抽象属性
3 )定义抽象方法: def hello():String // 只声明而没有实现的方法,就是抽象方法
abstract class Person {
 val name: String
 def hello(): Unit
}

继承&重写

1 )如果父类为抽象类,那么子类需要将抽象的属性和方法实现,否则子类也需声明
为抽象类
2 )重写非抽象方法需要用 override 修饰,重写抽象方法则可以不加 override
3 )子类中调用父类的方法使用 super 关键字
4 )子类对抽象属性进行实现,父类抽象属性可以用 var 修饰;
子类对非抽象属性重写,父类非抽象属性只支持 val 类型,而不支持 var
因为 var 修饰的为可变变量,子类继承之后就可以直接使用,没有必要重写
​​​​​​​

匿名子类

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")
 }
 }

难点

单例对象(伴生对象)

Scala 语言是 完全面向对象 的语言,所以并没有静态的操作(即在 Scala 中没有静态的概
念)。但是为了能够和 Java 语言交互(因为 Java 中有静态概念),就产生了一种特殊的对象
模拟类对象 ,该对象为 单例对象 。若单例对象名与类名一致,则称该单例对象这个类的
生对象 ,这个类的所有“静态”内容都可以 放置在它的伴生对象 中声明。
object Person{
    val country:String="China"
}
1 )单例对象采用 object 关键字声明
2 )单例对象对应的类称之为 伴生类 ,伴生对象的名称应该和伴生类名一致。
3 )单例对象中的属性和方法都可以通过伴生对象名(类名)直接调用访问。
//(1)伴生对象采用 object 关键字声明
object Person {
 var country: String = "China"
}
//(2)伴生对象对应的类称之为伴生类,伴生对象的名称应该和伴生类名一致。
class Person {
 var name: String = "bobo"
}
object Test {
 def main(args: Array[String]): Unit = {
 //(3)伴生对象中的属性和方法都可以通过伴生对象名(类名)直接调用访
问。
 println(Person.country)
 }
}

apply 方法

1 )通过 伴生对象 apply 方法, 实现不使用 new 方法创建对象。
2 )如果想让主构造器变成私有的,可以在 () 之前加上 private
3 apply 方法可以重载。
4 Scala obj(arg) 的语句实际是在调用该对象的 apply 方法,即 obj.apply(arg) 。用
以统一面向对象编程和函数式编程的风格。
5 )当使用 new 关键字构建对象时,调用的其实是类的构造方法,当直接使用类名构
建对象时,调用的其实时伴生对象的 apply 方法。
object Test {
 def main(args: Array[String]): Unit = {
 //(1)通过伴生对象的 apply 方法,实现不使用 new 关键字创建对象。
 val p1 = Person()
 println("p1.name=" + p1.name)
 val p2 = Person("bobo")
 println("p2.name=" + p2.name)
 }
}
//(2)如果想让主构造器变成私有的,可以在()之前加上 private
class Person private(cName: String) {
 var name: String = cName
}
object Person {
 def apply(): Person = {
 println("apply 空参被调用")
 new Person("xx")
 }
 def apply(name: String): Person = {
 println("apply 有参被调用")
 new Person(name)
}
//注意:也可以创建其它类型对象,并不一定是伴生类对象
}

特质(Trait

Scala 语言中,采用特质 trait (特征)来代替接口的概念 ,也就是说,多个类具有相同
的特质(特征)时,就可以将这个特质(特征)独立出来,采用关键字 trait 声明。
Scala 中的 trait 中即 可以有抽象属性和方法,也可以有具体的属性和方法 一个类可
以混入( mixin )多个特质 。这种感觉 类似于 Java 中的抽象类。
Scala 引入 trait 特征,第一可以替代 Java 的接口,第二个也是对单继承机制的一种
补充。
trait 特质名 {
    trait主体
}
trait PersonTrait {
 // 声明属性
 var name:String = _
 // 声明方法
 def eat():Unit={
 }
 // 抽象属性
 var age:Int
 
 // 抽象方法
 def say():Unit
}
通过查看字节码,可以看到特质=抽象类+接口
一个类具有某种特质(特征),就意味着这个类满足了这个特质(特征)的所有要素,
所以在使用时,也采用了 extends 关键字 ,如果有多个特质或存在父类,那么需要采用 with
关键字 连接。
没有父类:class 类名 extends 特质 1 with 特质 2 with 特质 3 …
有父类:class 类名 extends 父类 with 特质 1 with 特质 2 with 特质 3…
1 )类和特质的关系:使用继承的关系。
2 )当一个类去继承特质时,第一个连接词是 extends ,后面是 with
3 )如果一个类在同时继承特质和父类时,应当把父类写在 extends 后。
trait PersonTrait {
 //(1)特质可以同时拥有抽象方法和具体方法
 // 声明属性
 var name: String = _
 // 抽象属性
 var age: Int
// 声明方法
 def eat(): Unit = {
 println("eat")
 }
 // 抽象方法
 def say(): Unit
}
trait SexTrait {
 var sex: String
}
//(2)一个类可以实现/继承多个特质
//(3)所有的 Java 接口都可以当做 Scala 特质使用
class Teacher extends PersonTrait with java.io.Serializable {
 override def say(): Unit = {
 println("say")
 }
 override var age: Int = _
}
object TestTrait {
 def main(args: Array[String]): Unit = {
 val teacher = new Teacher
 teacher.say()
 teacher.eat()
 //(4)动态混入:可灵活的扩展类的功能
 val t2 = new Teacher with SexTrait {
 override var sex: String = "男"
 }
 //调用混入 trait 的属性
 println(t2.sex)
 }
}
1 )特质可以同时拥有抽象方法和具体方法
2 )一个类可以混入( mixin )多个特质
3 )所有的 Java 接口都可以当做 Scala 特质使用
4 动态混入 :可灵活的扩展类的功能
4.1 )动态混入:创建对象时混入 trait ,而无需使类混入该 trait
4.2 )如果混入的 trait 中有未实现的方法,则需要实现

特质叠加

冲突分为以下两种:
第一种,一个类( Sub )混入的两个 trait TraitA TraitB )中具有相同的具体方法,且
两个 trait 之间没有任何关系,解决这类冲突问题,直接在类( Sub )中重写冲突方法。

 

第二种,一个类( Sub )混入的两个 trait TraitA TraitB )中具有相同的具体方法,且
两个 trait 继承自相同的 trait TraitC ),及所谓的“钻石问题”,解决这类冲突问题, Scala
采用了 特质叠加 的策略。

 

trait Ball {
 def describe(): String = {
 "ball"
 }
}
trait Color extends Ball {
 override def describe(): String = {
 "blue-" + super.describe()
 }
}
trait Category extends Ball {
 override def describe(): String = {
 "foot-" + super.describe()
 }
}
class MyBall extends Category with Color {
 override def describe(): String = {
 "my ball is a " + super.describe()
 }
}
object TestTrait {
 def main(args: Array[String]): Unit = {
 println(new MyBall().describe())
 }
}

 

 

1 )案例中的 super ,不是表示其父特质对象,而是表示上述叠加顺序中的下一个特质,
即, MyClass 中的 super 指代 Color Color 中的 super 指代 Category Category 中的 super
指代 Ball
2 )如果想要调用某个指定的混入特质中的方法,可以增加约束: super[] ,例如
super[Category].describe()

特质自身类型

自身类型可实现依赖注入的功能。
不想继承,但需要用到类,可以用声明一个自身类型
class User(val name: String, val age: Int)
trait Dao {
 def insert(user: User) = {
 println("insert into database :" + user.name)
 }
}
trait APP {
 _: Dao =>
 def login(user: User): Unit = {
 println("login :" + user.name)
 insert(user)
 }
}
object MyApp extends APP with Dao {
 def main(args: Array[String]): Unit = {
 login(new User("bobo", 11))
 }
}

特质和抽象类的区别

1. 优先使用特质。一个类扩展多个特质是很方便的,但却只能扩展一个抽象类。
2. 如果你需要构造函数参数,使用抽象类。因为抽象类可以定义 带参数 的构造函数,
而特质不行(有无参构造)。

其他

类型检查和转换

1 obj.isInstanceOf[T] :判断 obj 是不是 T 类型。
2 obj.asInstanceOf[T] :将 obj 强转成 T 类型
3 classOf 获取对象的类名。
class Person{
}
object Person {
 def main(args: Array[String]): Unit = {
 val person = new Person
 //(1)判断对象是否为某个类型的实例
 val bool: Boolean = person.isInstanceOf[Person]
 if ( bool ) {
 //(2)将对象转换为某个类型的实例
 val p1: Person = person.asInstanceOf[Person]
 println(p1)
 }
 //(3)获取类的信息
 val pClass: Class[Person] = classOf[Person]
 println(pClass)
 }
}

枚举类和应用类

object Test {
 def main(args: Array[String]): Unit = {
 println(Color.RED)
 }
}
// 枚举类
object Color extends Enumeration {
 val RED = Value(1, "red")
 val YELLOW = Value(2, "yellow")
 val BLUE = Value(3, "blue")
}
// 应用类
object Test20 extends App {
 println("xxxxxxxxxxx");
}

Type 定义新类型

使用 type 关键字可以定义新的数据数据类型名称,本质上就是类型的一个别名
object Test {
 def main(args: Array[String]): Unit = {
 
 type S=String
 var v:S="abc"
 def test():S="xyz"
 }
}

来源

尚硅谷

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

返返返

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值