1.类
1)在scala中,类并不用声明为public
如果没有定义构造器,类会有一个默认的无参构造器
var修饰的变量,对外提供getter setter方法
val修饰的变脸,提供getter方法,没有setter方法
var name:String = _
_表示一个占位符,编译器会根据你变量的具体类型赋予相应的初始值
使用占位符,变量类型必须指定,val修饰的变量不能使用占位符
class StuDemo {
//_是占位符,使用时需要属性的类型信息
var name:String = _
//val使用前必须初始化,修饰的变量不能使用占位符
//除了接口或者抽象类,里面的属性都需要初始化
val age:Int = 10
//类私有字段,当前类的其它方法或者类的伴生对象可以访问
private var hobby:String = "traveing"
//生成get set方法,但方法是私有的,本类的方法可以访问
//对象私有字段--只有在当前对象方法可以调用
private [this] val cardinfo = "123456"
//没有get set方法
def compare(obj:StuDemo)={
if(this.age != obj.age) this.age-obj.age
//else if(this.cardinfo != obj.cardinfo)
}
}
object TestStu{
def main(args: Array[String]): Unit = {
//如果不定义构造方法,有一个无参的构造方法
val obj = new StuDemo
println(obj.age)
println(obj.name)
}
}
2)手动创建变量的getter和setter方法需要遵循以下原则:
(1) 字段属性名以“_”作为前缀,如:_x
(2) get方法定义为:def x = x
(3) set方法定义时,方法名为属性名去掉前缀,并加上后缀,后缀是:“def x=”
//字段属性名以“_”开始
class Point {
private var _x = 0
private var _y = 0
private val bound = 100
//get方法,方法名是属性名去掉“_”
def x = _x
//set方法,方法名是属性名去掉“_”,在后面加一个“_”
def x_=(newValue:Int) = {
if (newValue<bound)_x = newValue else println("nothing")
}
def y = _y
def y_= (newValue:Int)={
if (newValue < bound)_y =newValue else println("out of bound")
}
}
object testPoint{
def main(args: Array[String]): Unit = {
val pointObj = new Point()
println(pointObj.x)
pointObj.x_=(200)
pointObj.y_=(150)
}
}
3)Scala中定义类的构造方法
scala中构造分为主构造器和辅助构造器
(1)主构造的参数直接放置于类名之后
(2)主构造器会执行类定义中的所有语句
(3)通过private设置的主构造器的私有属性
(4)辅助构造器名称为this,(def this(…))通过不同参数进行区分,第一句一定是调用主构造方法或者其他的辅助构造方法
//主构造方法的参数直接放在类名之后
class ClassConstructor private (var name:String,val price:Double) {
//私有时直接 ClassConstructor private...私有构造方法不能直接调用构造对象
println(name + "," + price) //会执行类中的所有语句
private var weight:Double = 0
private var color:String = _
def myPrintln = println(name + "," + price)
//辅助构造方法,this,第一句一定是调用主构造方法或者其他的辅助构造方法
def this(name:String,price:Double,weight:Double){
this(name,price)
this.weight = weight
}
def this(name:String,price:Double,weight:Double,color:String){
this(name,price,weight)
this.color = color
}
}
object testConstructor{
def main(args: Array[String]): Unit = {
val obj = new ClassConstructor("apple",20.0,100.0)
//obj.myPrintln
}
}
2.特质
特质的定义除了使用关键字trait之外,与类定义无异
接口中可以:
声明一个有值的字段、声明一个抽象字段、声明一个=带有具体实现的方法、声明一个抽象方法
在triat中可以定义抽象方法,就与抽象类中的抽象方法一样,只要不给出方法的具体实现即可
类可以使用extends关键字继承trait,注意,这里不是implement,而是extends,在scala中没有implement的概念,无论继承类还是trait,统一都是extends
//特质(接口)
trait Flyable{
//接口中可以定义
//声明一个有值的字段
//接口中的字段:类中继承了这个字段,接口中的字段会直接添加到实现了(继承了)该接口的类中
//普通类中的字段:如果是普通的类,父类中的字段在子类中会有一个引用地址,指向父类的属性
val distant:Int = 100
//声明一个抽象字段
val height:Int
//声明一个=带有具体实现的方法
def fly:String = {
"I can fly"
}
//声明一个抽象方法
def fight:String
}
trait Logger{
def log(msg:String)
}
class ConsoleLogger extends Logger{
//类中实现抽象方法,重写抽象方法可以不用override
def log(msg: String): Unit = println(msg)
}
class Account{
var balance = 0.0
}
//一个以上的特质用with
class SavingAccount extends Account with Logger{
//override def log(msg: String): Unit = println("SavingAccount")
override def log(msg: String): Unit = println(msg)
def withdraw(amount:Double):Unit = {
if(amount > balance) log("余额不足")
else balance -= amount
}
}
//单继承,可以实现多接口
object TraitDemo {
def main(args: Array[String]): Unit = {
// val obj = new ConsoleLogger
// obj.log("trait test")
val obj = new SavingAccount
obj.withdraw(100)
}
}
类继承trait后,必须实现其中的抽象方法,实现时不需要使用override关键字
scala不支持对类进行多继承,但是支持多重继承trait,使用with关键字即可
特质继承类(特别点)
在Scala中,trait也可以继承自class,此时这个class就会成为所有继承该trait的类的父类
//特质继承类
class MyUtil{
def printmsg(msg:String) = println(msg)
}
trait MyTrait extends MyUtil{
def log (msg:String) = printmsg(msg)
}
class Demos(val name:String) extends MyTrait{
def sayHello:Unit = {
log(name+"0000000")
printmsg(name+"111111")
}
}
object TraitDemo2 {
def main(args: Array[String]): Unit = {
val obj = new Demos("zhangfasd")
obj.sayHello
}
}
3.抽象类
定义一个抽象类:abstract
如果某个类至少存在一个抽象方法或一个抽象字段,则该类必须声明为abstract。
abstract class Person{
//抽象字段,有初值的字段,抽象方法:没有方法体,是抽象方法,具体实现的方法、
val age = 20
var name:String
def id:Int //没有初始值,抽象字段
}
class Employ extends Person{
//实现抽象字段或者抽象方法
var name:String = "tom"
def id = name.hashCode
}
//object
object AbstactclassDemo {
def main(args: Array[String]): Unit = {
val obj = new Employ
println(obj.id)
}
}
4、对象
1)单例对象
在Scala中没有静态方法和静态字段,但是可以使用object这个语法结构来达到同样的目的
object ObjectTest {
def main(args: Array[String]): Unit = {
val s = SessionFactory
println(s.getSession())
println(s.getSession().size)
println(s.removeSession)
println(s.getSession().size)
}
}
class Session{
}
object SessionFactory{
print("SessionFactory被执行")
//计数器
var i = 5
//存放seesion对象
val sessions = new ArrayBuffer[Session]()
//session添加新的session
while(i>0){
sessions.append(new Session)
i -= 1
}
//获取session对象
def getSession() = sessions
//删除session对象
def removeSession:Unit = {
val session = sessions(0)
sessions.remove(0)
println("被删除的session对象"+session)
}
}
类和单例对象的区别是:
单例对象不能带参数,单例对象不能用new关键字实例化,所以没有机会传递给它实例化的参数。
单例对象在第一次访问的时候才会初始化。
当单例对象与某个类同名时,它被称为类的伴生对象,类和伴生对象必须定义在一个源文件里,类称为该单例对象的伴生类,类和他的伴生对象可以互相访问其私有成员。
不与伴生类共享名称的单例对象被称为独立对象,可以作为相关功能的工具类,或者scala应用程序的入口点。
2)伴生对象
在Scala的类中,与类名相同并且用object修饰的对象叫做伴生对象,类和伴生对象之间可以相互访问私有的方法和属性,他们必须存在同一个源文件中
//伴生对象要求:名字和类名是一致的,在一个源文件里
//优势:类和伴生对象之间可以互相访问彼此的私有属性或者方法
class AccountInfo{
//这里可以定义私有方法
var id = AccountInfo.newUniqueNumber()
private var balance = 0
}
object AccountInfo{
private var lastNumber = 0
private def newUniqueNumber()={
// val obj =new AccountInfo
// println(obj.balance)
lastNumber += 1//赋值语句的返回值是() Unit
println("lastNumber:"+lastNumber)
lastNumber//返回值
}
}
object ObjectTest2 {
def main(args: Array[String]): Unit = {
val obj = new AccountInfo
obj.id
}
}
对伴生对象的理解(单例对象)
伴生对象要求:名字和类名是一致的,在一个源文件里
优势:类和伴生对象之间可以互相访问彼此的私有属性或者方法,private this 修饰除外
3)应用程序对象
Scala程序都必须从一个对象的main方法开始,可以通过扩展App特质,不写main方法。
object Hello extends App{
println("Hello World")
}
5.unapply 和apply方法
unapply 和apply方法的区别,以及使用场景:
apply unapply 都在伴生方法中被定义,都是系统会隐式调用的
apply方法(注入):创建类的对象,不使用new关键字时被系统隐式调用,是创建对象 的工厂
unapply方法(提取):提取对象 的属性信息时,一般被用于模式匹配或者偏函数中
apply:
object AccountInfo1{
private var lastNunber = 0
//apply方法
def apply(a:Int)={ //被系统隐式调用,使用类名,没有new,会自动使用apply方法:var arr = Array(1,2,3,4,5)
println("apply 方法被调用")
lastNunber = a+1
lastNunber
}
}
object ObjectTest3 {
def main(args: Array[String]): Unit = {
println(AccountInfo1(1))
println(AccountInfo1.apply(2))
}
}
unapply:
object CustomID{
def apply(name:String) = s"$name---${Random.nextLong()}" // 差值器
//some() none
def unapply(CustomID:String): Option[String] = {
println("unapply方法被调用")
val name = CustomID.split("---").head
if(name.nonEmpty) Some(name) else None
}
}
object ObjectTest4 {
def main(args: Array[String]): Unit = {
val custoobj = CustomID("jerry")
custoobj match {
case CustomID(name) => println(name)
//相当于java中的default
case _ => println("not match")
}
}
}
6.继承
Scala中,让子类继承父类,与Java一样,也是使用extends关键字
继承就代表,子类可以从父类继承父类的属性和方法;然后子类可以在自己内部放入父类所没有,子类特有的属性和方法;使用继承可以有效复用代码
子类可以覆盖父类的属性和方法;但是如果父类用final修饰,则该类是无法被继承的,属性和方法用final修饰,属性和方法是无法被覆盖的
class Person1{
private var name = "tom"
val age = 0
def getName = name
}
class Student extends Person1{
private var score = 100
def getScore = score
//super调用父类的同名方法
//override重写父类的非抽象方法,非抽象字段
override val age = 0
override def getName: String = super.getName + " " +getScore
}
object ExtendsTest1 {
def main(args: Array[String]): Unit = {
val s = new Student
println(s.getScore)
println(s.getName)
}
//val per = new Person1
var per:Person1 = new Student
//
var student:Student = null
if(per.isInstanceOf[Student])
student=per.asInstanceOf[Student]
println(student.getScore)
}
注意:
(1)Override和super
Scala中,如果子类要覆盖一个父类中的非抽象方法,则必须使用override关键字,override还可以覆盖变量
此外,在子类覆盖父类方法之后,如果我们在子类中就是要调用父类的被覆盖的方法呢?那就可以使用super关键字,显式地指定要调用父类的方法
(2)父类子类转换
isInstanceOf和asInstanceOf
if(per.isInstanceOf[Stus])
stus = per.asInstanceOf[Stus]
println(stus)