Scala 面向对象
1、Scala 包
Scala也有包,包的命名使用规则和 java 完全一样
1.1、包的声明
- package com.scala.day
- 在scala 中一个 .scala 文件中一般会写多个类,所有的类会默认在一个包中
package aa{
class A
}
object Pack1{
def main(args: Array[String]): Unit = {
}
}
class A
package aa{
class A //两个不在一个包下面
}
1.2、包的使用
如何导包和导类:
- 在文件的最顶层 import java.util.HashMap
- 在代码的任何需要的地方导包,比如方法内部
- 通配符导入:
import java.util._
import java.util.{HashMap,TreeMap}
import java.util.{HashMap=>jHashMap}
import java.util.{HashMap=>_,_}
//import java.util.HashMap 在文件顶层
//import java.util.TreeMap
//import java.util.{HashMap,TreeMap} 同时导多个包
//import java.util._ 通配符导入,将util包下所有类全导入
//import java.util.{HashMap=>jHashMap} 导包时起个别名
//import java.util.{HashMap=>_,_} 屏蔽HashMap其余都想用
object Pack1{
def main(args: Array[String]): Unit = {
import java.util.HashMap //在方法内部
new HashMap[String,String]()
}
}
class A{
}
package aa{
class A
}
1.3、包对象
package object pack{
def foo(): Unit = println("foo...")
}
object Pack1{
def main(args: Array[String]): Unit = {
foo()
}
}
默认导入:
java:
- java.lang.*
scala:
1) java.lang._
2) scala._
3) scala.Predef._
2、类和对象
2.1、定义属性
- 在 Scala 中,类只要没加 private 的就都是public,且Scala中没有 public 关键字。
- 定义属性与定义普通变量完全一样
- 定义的属性在Scala中会自动定义为 private 还会实现getter、setterr 方法,但scala默认的getter、setter不满足标准的的javaBean规范,需要注解(@BeanProperty)加在属性定义前,即会增加标准getter、setter方法,用(@beanGetter)则只加标准getter方法。
object PackDemo {
def main(args: Array[String]): Unit = {
val user = new User
println(user)
println(user.age)
println(user.name)
user.eat()
}
}
class User{
//定义属性和定义变量完全一样
@BeanProperty var age:Int = 10
var name :String = "李四"
//给类定义方法
def eat() = {
println("eat:" + this.name)
}
}
2.2、类属性的初始化
1) 类的属性在scala中也可以让虚拟机自动给初始化值,但只能是var,且需要自动给类型,而不是推导。
2) 初始化的值分为三种:
- 数字型 0
- boolean false
- 其他所有类型 null
class User1{
var age:Int = _
var name:String = _
var isExit:Boolean = _
}
2.3、类的构造器
- 调用构造器创建对象时可以给属性赋值
- 构造器中里面声明的形参会自动成为类的属性
- 若 sex(未定义 var、val) 放在构造函数中时(如下)只能内部调用,外部不能用,若内部没人调用,则scala会帮我们自动优化(类似于删掉这个属性),但若内部调用(如下图def eat 中调用了) 则不会被优化。
- 类名后面跟的其实就是构造器,这个就是主构造器,一个类有唯一的一个。
- def this() :辅构造器,首行必须调用主构造器,辅构造器中的参数,仅仅是一个只能在当前的这个辅构造器内使用的普普通通的变量
- 辅构造器中有顺序要求,后面的辅构造器能调用前面的辅构造器,前面的不能调用后面的
- 主构造器中形参也能使用 @BeanProperty
object obj1{
def main(agrs: Array[String]) : Unit = {
var lisi:User2= new User2(age=10,name="lisi",sex="male")
println(lisi.age)
val user:User2 = new User
println(user.age)
}
}
class User2(@BeanProperty val age:Int,var name:String,sex:String){
def eat:Unit = {
println(sex)
}
//这种构造器叫做:辅构造器
//首行必须调用主构造器
def this(){
this(10,"abc","male")
}
def this(c:Int){
this() //间接调用主构造器
}
}
2.4、给类起别名
bject obj1{
def main(agrs: Array[String]) : Unit = {
type U = User2
val u:U = new U(age =10,name="a",sex="female")
println(u.age)
println(u.getClass.getName) //输出还是 User2
}
}
class User2(@BeanProperty val age:Int,var name:String,sex:String){
def eat:Unit = {
println(sex)
}
}
3、封装
3.1、权限修饰符
java:
- public
- protected (同包与子类)
- [default] friendly (同包)
- private (本类)
scala:
- [default] 默认都是 public
- protected (只能在子类中使用,同包内不行)
- private (本类)
scala 权限修饰的灵活性:可以定制
private[包A] (也可以对属性)
包A和包A的所有子类都可以访问
object Modifier{
def main(agrs: Array[String]) : Unit = {
val user:User = new User(age=10)
//若不开后门,则age这会报错
}
}
//对主构造器私有
//[modier] 使User类在本包中可以使用,其余的不可以
//modier是包名,可以自行定义(开后门)
class User private[modier](var age:Int){
private val a:Int = 10
}
4、继承
java:
- 类是单继承
- 接口 多实现
scala:
- 类也是单继承
- scala 没有接口,但是是提供了更强大的 trail (特质)
object Extends1{
def main(args: Array[String]): Unit = {
val b:B = new B
b.foo()
}
}
class A{
def foo = {
println("A foo......")
}
}
class B extends A{
override def foo() : Unit = { //方法的覆写(重写)
super.foo()
println("B foo...")
}
}
注意:
- 覆写方法,比较必须添加关键字 override,java 中可有可无
构造器的特征:
- java:父的静态 -> 子的静态 -> 父的构造 -> 子的构造
- scala:父的主构造 -> 子的主构造 -> 子构造
属性的覆写:
- val 只能覆写 val 和不带参数的 def
- var 只能覆写抽象的 var
object Extends1{
def main(args: Array[String]): Unit = {
val b1:B = new B
println(b1.a)
println(b1.b)
println(b1.c)
}
}
class A{
val a : Int = 10
var b : Int = 20
def c : Int = 30
}
class B extends A{
override val a : Int = 20 //可以
override var b : Int = 30 //运行出错 不可以
override val c : Int = 40 //可以
}
注意:
- 在java中,方法有多态,属性没有多态
- 在scala中,不仅方法有多态,属性也有多态
object Extends2{
def main(args: Array[String]): Unit = {
val b1:B1 = new B1
val a1:A1 = b1
println(b1.a) //20
println(a1.a) //20 但在 java中输出为10 java中属性没有多态
}
}
class A1{
val a:Int = 10
}
class B1 extends A1{
override val a : Int = 20
}
5、抽象属性和抽象方法
java中有抽象类,scala中也有抽象类
scala中的抽象类可以有哪些成员:
- 普通类可以有的,抽象类都可以
- 抽象类可以有抽象方法和抽象字段(属性)
- 抽象类不能直接创建对象,只能创建他的子类对象
object Abs1{
def main(args[String]): Unit = {
val b:B = new B
b.foo()
}
}
abstract class A(var a : Int){
//属性只有声明,不初始化,这就是抽象字段
var b : Int
//方法只有声明,没有实现,就是抽象方法
def foo() : Int
}
class B extends A(20){
override var b : Int = _
override def foo() : Int = {
println("foo....")
10
}
}
6、单例对象(伴生对象)
1、java实现单例:
- 饿汉式
- 懒汉式
2、scala中单例:
- 使用object关键字声明出来的对象就是一个单例对象,独立对象
- 任何的对象(object,也可以是new),只要提供了apply方法,都可以使用方法一样去调用对象,实际就是在调用apply方法
- 如果在同一个scala文件中,一个object的名字和一个class的名字一样,则它们分别叫伴生对象,半身类
- 编译成字节码后,伴生对象是静态方法,半生类是非静态(对象方法)
object Single1{
def main(args[String]): Unit = {
A() //等价于 A.apply()
}
}
object A{ //伴生对象
def foo() : Unit = println("foo...")
def apply():Int = {
println("apply")
10
}
}
class A{ //伴生类
}