目录
(1)基本语法
package 包名
(2)Scala包的三大作用(和 Java 一样)
1)区分相同名字的类;
2)可以很好的管理类;
3)控制访问范围;
包命名
(1)命名规则
只能包含数字、字母、下划线、小圆点.,不能用数字、关键字开头。
(2)命名规范
一般是小写字母+小圆点
com.公司名.项目名.业务模块名
包说明
(1)说明
Scala有两种包的管理风格,一种方式和Java的包管理风格相同,包名用“.”进行分隔以表示包的层级关系,如com.zj.scala。
另一种风格,通过嵌套的风格表示层级关系
package com{
package zj{
package scala{
}
}
}
第二种风格有以下特点:
1)一个源文件中可以声明多个package;
2)子包中的类可以直接访问父包中的内容,而无需导包;
包对象
在Scala中可以为每个包定义一个同名的包对象,定义在包对象中的成员,作为其对应包下所有class和object的共享变量,可以被直接访问。
- package com {
- object Test01 {
- val out: String = "out"
- def main(args: Array[String]): Unit = {
- println(name)
- println(out)
- }
- }
- }
-
- package object com {
- val name : String = "com"
- }
导包说明
import.com.zj.test | 引入com.zj包下的test(class和object) |
import.com.zj._ | 引入com.zj下的所有成员 |
import.com.zj.test._ | 引入com.zj下test的object所有成员 |
import.com.zj.{test,test2} | 引入com.zj下的test和test2 |
import.com.zj.{test=>TEST} | 引入com.zj下的test并改名为TEST |
import.com.zj.{test=>TEST,_} | 引入com.zj下的所有成员,并将test改名为TEST |
import.com.zj.{test=>_,_} | 引入com.zj下的屏蔽test类 |
new_root_.java.util.HashMap | 引入的java绝对路径 |
scala的三个默认包:import java.lang._ import scala._ import scala.Predef._
访问权限
在Java中访问权限分为:public,private,protected和默认。Scala中可以通过类似的修饰符达到同样的效果。但是使用上有区别。
(1)Scala中无public关键字,但Scala中属性和方法的默认访问权限为public。
(2)private为私有权限,只在类的内部和伴生对象中可用。
(3)protected为受保护权限,Scala中受保护权限比Java中更严格,同类、子类可以访问,同包无法访问。
(4)private[包名]增加包访问权限,包名下的其他类也可以使用。
- class Person {
- private var name: String = "jeffry"
- protected var age: Int = 20
- private[faceobject] var sex: String = "男"
- def say(): Unit = {
- println(name)
- println(age)
- println(sex)
- }
- }
-
- object Test01 {
- def main(args: Array[String]): Unit = {
- //
- val person = new Person
- person.say()
- // println(person.name) //不能使用
- // println(person.age) //不能使用
- println(person.sex)
- }
- }
-
- class Teacher extends Person {
- def test(): Unit = {
- // this.name //不能使用
- this.age
- this.sex
- }
- }
-
- class Person02 {
- def test(): Unit = {
- // new Person().name //不能使用
- // new Person().age //不能使用
- new Person().sex
- }
- }
定义类
基本语法:【修饰符】class 类名 {类体}
(1)Scala语法中,类并不声明为public,所有这些类都具有公有可见性(即默认就是public);
(2)一个Scala源文件可以包含多个类;
属性
基本语法:【修饰符】var/val 属性名称 【:类型】 = 属性值
注:Bean属性(@BeanPropetry)可以自动生成规范的setXxx/getXxx方法。
- import scala.beans.BeanProperty
-
- class Person03 {
- var name: String = "jeffry"
- var age: Int = _ // _表示给属性一个默认值
- //Bean 属性(@BeanProperty)
- @BeanProperty var sex: String = "男"
- }
-
- object Tets02 {
- def main(args: Array[String]): Unit = {
- var person = new Person03()
- println(person.name)
- person.setSex("男")
- println(person.getSex)
- }
- }
方法
基本语法:def 方法名(参数列表)【:返回值类型】 = {方法体}
- class SUM {
- def Sum(a:Int,b:Int): Int = {
- a + b
- }
- }
- object Tets03 {
- def main(args: Array[String]): Unit = {
- val sum = new SUM()
- println(sum.Sum(5,10))
- }
- }
创建对象
基本语法:var/val 对象名 【:类型】 = new 类型()
(1)val修饰对象,不能改变对象的引用(即:内存地址),可以改变对象属性的值。
(2)var修饰对象,可以修改对象的引用和修改对象的属性值。
(3)自动推导变量类型不能多态,所以多态需要显示声明。
- class Person03 {
- var name: String = "jeffry"
- }
-
- object Tets02 {
- def main(args: Array[String]): Unit = {
- val person = new Person03()
- person.name = "zj"
- println(person.name)
- }
- }
构造器
和Java一样,Scala构造对象也需要调用构造方法,并且可以有任意多个构造方法。
Scala类的构造器包括:主构造器和辅助构造器
基本语法:
class 类名(形参列表) { // 主构造器
// 类体
def this(形参列表) { // 辅助构造器
}
def this(形参列表) { //辅助构造器可以有多个...
}
}
说明:
(1)辅助构造器,函数的名称this可以有多个,编译器通过参数的个数及类型来区分。
(2)辅助构造方法不能直接构建对象,必须直接或者间接调用主构造方法。
(3)构造器调用其他另外的构造器,要求被调用构造器必须提前声明。
- class Person04 {
- var name : String = _
- var age : Int = _
- def this(age: Int) {
- this()
- this.age = age
- println("辅助构造器1")
- }
-
- def this(age: Int,name: String) {
- this()
- this.age = age
- this.name = name
- println("辅助构造器2")
- }
- println("主构造器")
- }
- object Test04 {
- def main(args: Array[String]): Unit = {
- val person = new Person04(18)
- }
- }
构造器参数
(1)未用任何修饰符修饰,这个参数就是一个局部变量;
(2)var修饰参数,作为类的成员属性使用,可以修改;
(3)val修饰参数,作为类只读属性使用,不能修改;
封装就是把抽象出的数据和对数据的操作封装在一起,数据被保护在内部,程序的其它部分只有通过被授权的操作(成员方法),才能对数据进行操作。Java封装操作如下:
(1)将属性进行私有化;
(2)提供一个公共的set方法,用于对属性赋值;
(3)提供一个公共的get方法,用于获取属性的值;
Scala中的public属性,底层实际为private,并通过get方法(obj.field())和set方法 (obj.field_=(value))对其进行操作。所以Scala并不推荐将属性设为private,再为其设置public的get和set方法的做法。但由于很多Java框架都利用反射调用getXXX和setXXX方法,有时候为了和这些框架兼容,也会为Scala的属性设置getXXX和setXXX方法(通过 @BeanProperty 注解实现)。
基本语法:class 子类名· extends 父类名 {类体}
(1)子类继承父类的属性和方法;
(2)scala是单继承;
案例:
(1)继承的调用顺序:父类构造器->子类构造器
- class Person05(names: String) {
- var name = names
- var age : Int = _
-
- def this(nameP: String,ageP: Int) {
- this(nameP)
- this.age = ageP
- println("父类辅助构造器")
- }
- println("父类主构造器")
- }
-
- class Person06(names : String,ages : Int) extends Person05(names,ages) {
- var no : Int = _
- def this(names : String,ages : Int,no : Int) {
- this(names,ages)
- this.no = no
- println("子类的辅助构造器")
- println(names,ages,no)
- }
- }
-
- object Test05 {
- def main(args: Array[String]): Unit = {
- new Person06("jeffry",20,1001)
- }
- }
重写
Scala中属性和方法都是动态绑定,而Java中只有方法为动态绑定。
- class Person07 {
- val name : String = "person07"
- def say() : Unit = {
- println("原方法")
- }
- }
-
- class Person08 extends Person07 {
- override val name: String = "person08"
-
- override def say(): Unit = {
- println("重写方法!")
- }
- }
-
- object Test06 {
- def main(args: Array[String]): Unit = {
- val person01 : Person07 = new Person07()
- println(person01.name)
- person01.say()
-
- val person02 : Person08 = new Person08()
- println(person02.name)
- person02.say()
- }
- }
抽象属性和抽象方法
基本语法:
(1)定义抽象类:abstract class Person{} //通过 abstract 关键字标记抽象类;
(2)定义抽象属性:val|var name:String //一个属性没有初始化,就是抽象属性;
(3)定义抽象方法:def hello():String //只声明而没有实现的方法,就是抽象方法;
案例:
- abstract class Person {
- val name : String
- def say() : Unit
- }
- class Teacher extends Person {
- val name : String = "teacher"
-
- override def say(): Unit = {
- println("hello teacher!!!!!")
- }
- }
继承和重写
(1)如果父类为抽象类,那么子类需要将抽象的属性和方法实现,否则子类也需声明为抽象类;
(2)重写非抽象方法需要用override修饰,重写抽象方法则可以不加override;
(3)子类中调用父类的方法使用super关键字;
(4)子类对抽象属性进行实现,父类抽象属性可以用var修饰;
(5)子类对非抽象属性重写,父类非抽象属性只支持val类型,而不支持var类型,因为var修饰的为可变变量,子类继承之后就可以直接使用,没有必要重写。
匿名子类
和Java一样,通过包含带有定义或重写的代码块的方式创建一个匿名的子类。
案例:
- abstract class Person {
- val name : String
- def say() : Unit
- }
-
- object Test07 {
- def main(args: Array[String]): Unit = {
- val person = new Person {
- override val name: String = "jeffry"
-
- override def say(): Unit = {
- println("hello jeffry!!!!")
- }
- }
- }
- }
Scala语言是完全面向对象的语言,所以并没有静态的操作。但是为了能够和Java语言交互,就产生了一种特殊的对象来模拟类对象,该对象为单例对象。若单例对象名与类名一致,则称该单例对象为这个类的伴生对象,这个类的所有“静态”内容都可以放置在它的伴生对象中声明。
单列对象语法
基本语法:
object person {
val name:String=“jeffry”
}
(1)单例对象采用 object 关键字声明。
(2)单例对象对应的类称之为伴生类,伴生对象的名称应该和伴生类名一致。
(3)单例对象中的属性和方法都可以通过伴生对象名(类名)直接调用访问。
- object Person {
- var names : String = "Tom"
- }
- class Person {
- var name : String = "jeffry"
- }
-
- object Test07 {
- def main(args: Array[String]): Unit = {
- //单例对象中的属性和方法都可以通过伴生对象名(类名)直接调用访问。
- println(Person.names)
- val person = new Person()
- println(person.name)
- }
- }
apply方法
(1)通过伴生对象的apply方法,实现不使用new方法创建对象。
(2)如果想让主构造器变成私有的,可以在()之前加上private。
(3)apply方法可以重载。
(4)Scala中obj(arg)的语句实际是在调用该对象的apply方法,即obj.apply(arg)。用以统一面向对象编程和函数式编程的风格。
(5)当使用new关键字构建对象时,调用的其实是类的构造方法,当直接使用类名构建对象时,调用的其实时伴生对象的apply方法。
案例:
- object Test07 {
- def main(args: Array[String]): Unit = {
- //通过伴生对象的 apply 方法,实现不使用 new 关键字创建对象
- val P = Person()
- println("P.name=" + P.name)
-
- val P1 = Person("Tom")
- println("P1.name=" + P1.name)
- }
- }
-
- //如果想让主构造器变成私有的,可以在()之前加上 private
- class Person private(names : String) {
- var name : String = names
- }
- object Person {
- def apply(): Person = {
- println("apply空参被调用")
- new Person("jeffry")
- }
-
- def apply(names: String): Person = {
- println("apply有参被调用")
- new Person(names)
- }
- }
Scala语言中,采用特质trait(特征)来代替接口的概念,也就是说,多个类具有相同的特质时,就可以将这个特质独立出来,采用关键字trait声明。
Scala中的trait中即可以有抽象属性和方法,也可以有具体的属性和方法,一个类可以混入多个特质。这种感觉类似于Java中的抽象类。
Scala引入trait特征,第一可以替代Java的接口,第二个也是对单继承机制的一种补充。
基本语法:
trait 特质名 {
trait 主体
}
案例:
- trait PersonTrait {
- //声明属性
- var name : String = _
- //声明方法
- def say() : Unit = {}
- //抽象属性
- var age : Int
- //抽象方法
- def sayy() : 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 {
- //特质可以同时拥有抽象方法和具体方法
- //声明属性
- var name : String = _
- //抽象属性
- var age : Int
- //声明方法
- def say() : Unit = {}
- //抽象方法
- def sayy() : Unit
- }
-
- trait SexTrait {
- var sex : String
- }
- //一个类可以实现/继承多个特质
- //所有的java接口都可以当做scala特质使用
- class TeacherTest extends PersonTrait with java.io.Serializable {
- override def sayy(): Unit = {
- println("sayy")
- }
- override var age: Int = _
- }
- object Test08 {
- def main(args: Array[String]): Unit = {
- val teacher = new TeacherTest
- teacher.say()
- teacher.sayy()
- //动态混入:可灵活的扩展类的功能
- val teacher2 = new TeacherTest with SexTrait {
- override var sex: String = "男"
- }
- //调用混入trait的属性
- println(teacher2.sex)
- }
- }
特质叠加
由于一个类可以混入(mixin)多个trait,且trait中可以有具体的属性和方法,若混入的特质中具有相同的方法(方法名,参数列表,返回值均相同),必然会出现继承冲突问题。
冲突分为以下两种:
第一种,一个类(Sub)混入的两个trait(TraitA,TraitB)中具有相同的具体方法,且两个trait之间没有任何关系,解决这类冲突问题,直接在类(Sub)中重写冲突方法。
第二种,一个类(Sub)混入的两个trait(TraitA,TraitB)中具有相同的具体方法,且两个trait继承自相同的trait(TraitC),及所谓的“钻石问题”,解决这类冲突问题,Scala采用了特质叠加的策略。所谓的特质叠加,就是将混入的多个trait中的冲突方法叠加起来,案例如下,
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()}}
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("Dao :"user.name)
- }
- }
- trait APP {
- _: Dao =>
-
- def login(user: User) : Unit = {
- println("login :" + user.name)
- insert(user)
- }
- }
- object Test09 extends APP with Dao {
- def main(args: Array[String]): Unit = {
- login(new User("jeffry",20))
- }
- }
特质和抽象类的区别
(1)优先使用特质。一个类扩展多个特质是很方便的,但却只能扩展一个抽象类。
(2)如果你需要构造函数参数,使用抽象类。因为抽象类可以定义带参数的构造函数,而特质不行,特质是有无参构造。
类型检查和转换
(1)obj.isInstanceOf[T]:判断obj是不是T类型。
(2)obj.asInstanceOf[T]:将obj强转成T类型。
(3)classOf获取对象的类名。
- class Person11 {
-
- }
-
- object Test10 {
- def main(args: Array[String]): Unit = {
- val person = new Person11
- // 判断是不是person类型
- val bool : Boolean = person.isInstanceOf[Person11]
- // 强转成person类型。
- if (bool) {
- val p1 : Person11 = person.asInstanceOf[Person11]
- println(p1)
- }
- // 获取对象的类名
- val PClass : Class[Person11] = classOf[Person11]
- println(PClass)
- }
- }
枚举类型和应用类型
枚举类:需要继承Enumeration
应用类:需要继承App
- object Test11 {
- def main(args: Array[String]): Unit = {
- println(Color.BLUE)
- println(APPS)
- }
- }
- //枚举类
- object Color extends Enumeration {
- val RED = Value(1,"red")
- val BLUE = Value(2,"blue")
- val YELLOW = Value(3,"yellow")
- }
-
- //应用类
- object APPS extends App {
- println("++++++++++++")
- }
type定义新类型
使用type关键字可以定义新的数据数据类型名称,本质上就是类型的一个别名。
- def main(args: Array[String]): Unit = {
- type S=String
- var v:S="abc"
- def test():S="jeffry"
- }