您现在的位置是:首页 >学无止境 >Scala面向对象网站首页学无止境
Scala面向对象
Scala 的面向对象思想和Java 的面向对象思想和概念是一致的。
Scala 中语法和 Java 不同,补充了更多的功能。
6.1类和对象详解
6.1.1组成结构
-
构造函数: 在创建对象的时候给属性赋值
-
成员变量:
-
成员方法(函数)
-
局部变量
-
代码块
6.1.2构造器
每个类都有一个主构造器,这个构造器和类定义"交织"在一起类名后面的内容就是主构造器,如果参数列表为空的话,()可以省略 scala的类有且仅有一个主构造器,要想提供更加丰富的构造器,就需要使用辅助构造器,辅助构造器是可选的,它们叫做this def this
// 类默认有一个无参的主构造函数
class User {
}
val user: User = new User
// 两个参数的主构造函数
class User2(val name: String, age: Int) {
}
val user2 = new User2("jim", 23)
// 使用val修饰的变量默认是成员变量,对象可以访问
// user2.age // age没有使用val或者var修饰 所以不能被访问,他不是一个成员变量,而是一个局部变量
//辅助构造器
class User3 {
var name: String = _
var age: Int = _
// 辅助构造函数
def this(name: String, age: Int) {
// 构造函数中的首行必须调用主构造函数或者其他构造函数
this()
this.name = name
this.age = age
}
// 辅助构造函数
def this(msg: String) = {
// 首行调用一个构造
this("ww", 12)
println(msg)
}
}
val u1 = new User3()
val u2 = new User3("")
val u3 = new User3("lisi", 23)
println(u3.name)
总结:
-
有两类构造器:主构造器,辅助构造器
-
构造器的定义位置:主构造器和类交织在一起,class Student2(val name: String, var age: Int)
-
辅助构造器是一个特殊的方法,定义在类中 def this(name:String,age:Int,gender:String)
-
辅助构造器,第一行必须调用主构造器(或者其他的辅助构造器)
-
辅助构造器的参数不能和主构造器的参数完全一致(参数个数,参数类型,参数顺序)
-
可以定义空参的辅助构造器,但是主构造器的参数必须进行初始化赋值
-
作用域:辅助构造器的变量作用域,只在方法中,主构造器的作用域是类中除了成员属性和成员方法之外的所有范围(可以通过反编译查看源码)
构造器的参数说明
-
主构造函数中使用val 和 var修饰的变量为成员变量
-
val 修饰的变量默认只有getter方法 一要初始化
-
var 修饰的变量默认有 get和set方法 直接点属性操作 使用 _ 占位可以稍后赋值
-
@BeanProperty会生成getMsg setMsg方法
6.1.3成员方法/函数
在类的成员位置定义的函数或者方法是类的成员的一部分
6.1.4代码块
在类或者对象中的代码块在实例化的时候会被调用
-
在类成员位置的代码块 构造代码块 每次创建对象都会执行一次
-
在object中成员位置的代码块是静态代码块 只执行一次
-
代码有返回值
6.1.5object类的底层原理
package com.doit.day01.day02
//如果构造器中的变量,不加var 或者val 那他就是一个局部变量
//加了var 或者val 的话他就是一个私有的成员变量
class Student1(var id: Int, val name: String) {
def sayHello: Unit = {
println(name + ":你好")
}
val sayFunc = () => {
println("hello:" + name)
}
}
object Student2{
var id: Int = 1
//如果在成员变量的位置上给一个_作为占位符,相当于是给他赋了一个默认值啊
var name: String =_
def sayHello: Unit = {
println(name + ":你好")
}
val sayFunc = (x:String) => {
println("hello:" + name + x)
}
}
object Demo01_面向对象 {
def main(args: Array[String]): Unit = {
Student2.sayFunc("a")
val student1: Student1 = new Student1(1, "zhangsan")
println(student1.name)
println(student1.id)
// student1.name = "lisi" 用val 修饰的,不能修改
student1.id = 2
println(student1.id)
student1.sayHello
student1.sayFunc()
println(Student2.name)
}
}
需求1:1.定义一个object,里面放一个成员:base = 100
2.定义一个工具方法:求两数之和,如果和<base 返回和,否则返回base
3.定义一个工具函数:求两数的差,并且返回(差值<base 就返回base,否则返回差值)
4.定义一个工具函数:求三个数的最大值,如果最大值<base 就返回base,否则返回最大值
object Max {
val base = 100
def sum(i: Int, j: Int) = {
if (i + j < base) base else i + j
}
val cha = (i: Int, j: Int) => {
if (i - j < base) base else i - j
}
val max = (a: Int, b: Int, c: Int) => {
var mx = a
if (b > mx) mx = b
if (c > mx) mx = c
if (mx > base) mx else base
}
}
伴生类和伴生对象
条件 1:在同一个源文件中, 条件 2:对象名和类名相同
//类名和object的名称一致
//类是对象的伴生类
//对象是类的伴生对象
class Demo6(val name: String) {
}
object Demo6 {
}
条件 2:伴生对象和伴生类之间可以互相访问彼此的私有属性和私有方法
package com.doit.day01.day02
/**
* 伴生对象的用途:
* 1.可以将静态的成员变量和普通成员变量分别声明
* 2.伴生对象自己内部定义了一个apply方法,可以简化创建对象(类的实例构造)
* 3.伴生对象自己定义了一个unapply方法,可以用于模式匹配
*/
class Car(var brand: String, var price: Double) {
def sayHello(): Unit ={
println("hello")
}
private val color: String = Car.color
Car.start()
}
object Car {
var color :String = "red"
def start(): Unit ={
println("汽车启动了,嗡~~~~~~~~")
}
}
object Demo02_伴生对象 {
def main(args: Array[String]): Unit = {
val car: Car = new Car("华为", 9.9)
println(car.brand)
println(car.price)
car.sayHello()
Car.start()
}
}
伴生对象的底层原理:
//decompiled from Car.class
package com.doit.day01.day02;
import scala.Predef.;
import scala.reflect.ScalaSignature;
@ScalaSignature(
bytes = "u0006u0001E3Au0001E u00015!Au0011u0005u0001BAu0002u0013u0005!u0005u0003u0005/u0001 u0005
u0011"u00010u0011!)u0004A!A!Bu0013u0019u0003u0002u0003u001cu0001u0005u0003u0007Iu0011Au001c u0011mu0002!u00111Au0005u0002qBu0001Bu0010u0001u0003u0002u0003u0006Ku0001u000fu0005u0006u007fu0001! u0001u0011u0005u0006u000bu0002! ARu0004u0006u000fFA u0001u0013u0004u0006!EA !u0013u0005u0006u007f)! Au0013u0005u0017*u0001
u0011"u0001#u0011u001da%u00021Au0005u00025Caau0014u0006!Bu0013u0019u0003"u0002)u000b u00031%aA"be*u0011!cEu0001u0006Iu0006LG
u0006u0003)U Qu0001Z1zaER!AFfu0002 u0011|u0017u000eu001eu0006u00021u0005u00191m\7u0004u0001Mu0011u0001au0007 u00039}iu0011!u0006u0002=u0005)1oY1mC&u0011u0001%u0002u0007u0003:L(+u001a4u0002u000b u0014u0018Mu001c3u0016u0003
u0002"u0001Ju0016u000fu0005u0015Ju0003Cu0001u0014u001eu001bu00059#Bu0001u0015u001au0003u0019a$o\8u}%u0011!&Hu0001u0007!J,G-u001a4
u00051j#AB*ue&twMu0003u0002+;u0005I!M]1oI~#S-u001du000bu0003aMu0002"u0001Hu0019
u0005Ij"u0001B+oSRDqu0001u000eu0002u0002u0002u0003u00071%Au0002yIE
aAu0019:b]u0012u0004u0013!u00029sSu000e,W#u0001u001du0011u0005qIu0014Bu0001u001eu001eu0005u0019!u.u001e2mKu0006Iu0001O]5dK~#S-u001du000bu0003auBqu0001Nu0003u0002u0002u0003u0007u0001(u0001u0004qe&u001cW
Iu0001u0007y%tu0017u000eu001e u0015u0007u0005u001bE u0005u0002Cu00015 u0011u0003Cu0003"u000fu0001u00071u0005Cu00037u000fu0001u0007u0001(u0001u0005tCfDU
u001c7p)u0005u0001u0014aA"beBu0011!IC
u0003u0015m!u0012u0001Su0001u0006G>dwN]u0001
G>dwN]0%KF$"u0001
( u000fQju0011u0011!au0001Gu000511mu001c7peu0002
Qau001d;beRu0004"
)
public class Car {
private String brand;
private double price;
public static void start() {
Car$.MODULE$.start();
}
public static void color_$eq(final String x$1) {
Car$.MODULE$.color_$eq(var0);
}
public static String color() {
return Car$.MODULE$.color();
}
public String brand() {
return this.brand;
}
public void brand_$eq(final String x$1) {
this.brand = x$1;
}
public double price() {
return this.price;
}
public void price_$eq(final double x$1) {
this.price = x$1;
}
public void sayHello() {
.MODULE$.println("hello");
}
public Car(final String brand, final double price) {
this.brand = brand;
this.price = price;
super();
}
}
//decompiled from Car$.class
package com.doit.day01.day02;
import scala.Predef.;
public final class Car$ {
public static Car$ MODULE$;
private String color;
static {
new Car$();
}
public String color() {
return this.color;
}
public void color_$eq(final String x$1) {
this.color = x$1;
}
public void start() {
.MODULE$.println("汽车启动了,嗡~~~~~~~~");
}
private Car$() {
MODULE$ = this;
this.color = "red";
}
}
伴生对象用途:
-
可以将静态的成员变量和普通成员变量分别声明(class中没办法添加静态成员,需要经过object类来添加)
-
伴生对象自己内部定义了一个apply方法,可以简化创建对象(类的实例构造)
-
伴生对象自己定义了一个unapply方法,可以用于模式匹配
6.1.6apply方法
使用此方法时,可以在main函数中不通过new来创建一个对象,即可以不用专门的一次一次地进行实例化,加载创建对象的这个类的时候,会自动调用apply这个方法,类似Java中的static静态块。
-
通过伴生对象的 apply 方法,实现不使用 new 方法创建对象。
-
apply 方法可以重载。
-
Scala 中 obj(arg)的语句实际是在调用该对象的 apply 方法,即 obj.apply(arg)。用以统一面向对象编程和函数式编程的风格。
-
当使用 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)
}
}
权限修饰符
在 Java 中,访问权限分为:public,private,protected 和默认。在 Scala 中,你可以通过类似的修饰符达到同样的效果。但是使用上有区别。
(1)Scala 中属性和方法的默认访问权限为 public,但 Scala 中无 public 关键字。
(2)private 为私有权限,只在类的内部和伴生对象中可用。
(3)protected 为受保护权限,Scala 中受保护权限比 Java 中更严格,同类、子类可以访问,同包无法访问。
(4)private[包名]增加包访问权限,包名下的其他类也可以使用
代码演示:
class Person {
private var name: String = "bobo"
protected var age: Int = 18
private[test] var sex: String = "男"
def say(): Unit = {
println(name)
}
}
object Person {
def main(args: Array[String]): Unit = {
val person = new Person
person.say()
println(person.name)
println(person.age)
}
}
class Teacher extends Person {
def test(): Unit = {
this.age
this.sex
}
}
class Animal {
def test: Unit = {
new Person().sex
}
}
特质和抽象类
6.3.1特质
Trait(特质)相当于 java 的接口。比接口功能更强大。特质中可以定义属性和抽象方法和方法的实现。
Scala 的类只能够继承单一父类,但是可以实现(继承,混入)多个特质(Trait),使用的关键字是 with 和 extends
trait 特质名 {
trait 主体
}
//如何使用特质:
没有父类:class 类名 extends 特质 1 with 特质 2 with 特质 3 …
有父类:class 类名 extends 父类 with 特质 1 with 特质 2 with 特质 3…
trait PersonTrait {
// 声明属性
var name:String = _
// 声明方法
def eat():Unit={
}
// 抽象属性
var age:Int
// 抽象方法
def say():Unit
}
特质的动态混入
1.创建对象时混入 trait,而无需使类混入该 trait
2.如果混入的 trait 中有未实现的方法,则需要实现
代码演示:
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)
}
}
抽象类
在 Scala 中, 使用 abstract 修饰的类称为抽象类. 在抽象类中可以定义属性、未实现的方法(抽象方法)和具体实现的方法。 含有抽象方法的类就是抽象类
-
抽象类中的属性
-
抽象方法
-
具体实现的方法
-
类的单继承
示例:
/*
* abstract 修饰的类是一个抽象类
* */
abstract class Animal {
println("Animal's constructor ....")
// 定义一个 name 属性
val name: String = "animal"
// 没有任何实现的方法
def sleep()
// 带有具体的实现的方法
def eat(f: String): Unit = {
println(s"$f")
}
}
抽象类的继承和重写
-
如果父类为抽象类,那么子类要么也是抽象类,要么就需要重写父类中的所有的抽象方法和抽象的成员变量
-
重写非抽象方法需要用 override 修饰,重写抽象方法则可以不加 override。
-
子类中调用父类的方法使用 super 关键字,在子类重写了父类的方法后,如果不加super,直接写方法名调用的就是子类重写后的,如果加了,调用的还是父类的
-
子类对抽象属性进行实现,父类抽象属性可以用 var 修饰;子类对非抽象属性重写,父类非抽象属性只支持 val 类型,而不支持 var(var修饰具体方法和变量不好重写)
样例类
使用case修饰的类就是样例类(封装数据,模式匹配)
-
构造器中的参数默认是val修饰的[成员,赋值1次]
-
样例类会自动创建伴生对象, 同时在里面实现;的apply和unapply方法 ,创建对象的时候不用new
-
很好的支持匹配模式
-
默认实现了自己的toString , hashCode , copy , equals,序列化方法
定义一个样例类:
case class Person(var name:String , var age:Int)
{}//如果类中没有别的需要定义的,可以不写大括号
case class 和 class 的一些区别:
-
case class 在初始化的时候,不用 new,而普通类初始化时必须要 new。
-
case class 重写了 toString 方法。 默认实现了 equals 和 hashCode
-
case class 实现了序列化接口 with Serializable
-
case class 支持模式匹配(最重要的特征),所有 case class 必须要有参数列表
-
有参数用 case class,无参用 case object
6.5继承和多态
基本语法
class 子类名 extends 父类名 { 类体 }
(1)子类继承父类的属性和方法
(2)scala 是单继承
案例实操:
(1)子类继承父类的属性和方法
(2)继承的调用顺序:父类构造器->子类构造器
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("子类的辅助构造器")
}
println("子类主构造器")
}
object Test {
def main(args: Array[String]): Unit = {
new Emp("z3", 11,1001)
}
}