目录
包
(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)
}
}
特质(Trait)
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"
}