Scala进阶

来源:互联网 发布:非主流 知乎 编辑:程序博客网 时间:2024/06/06 00:46

Scala进阶

定义类

class User{  //类成员必须初使化,  var name:String=null  @BeanProperty var alias:String="caspar"  private[this] var age=null  //println将作为主构建器中的一部分,在创建对象时被执行  println("constructing user ........")  //重写toString()方法  override def toString()= name + ":"+ alias}//通过继承App,定义一个应用程序对象//扩展App后,程序可以直接运行,而不需要自己定义main方法,代码更简洁object UserTest extends App{  var user = new User()  user.name="caspar" //直接修改,但其实调用的是p.name_=("jonh")  user.alias_=("csp")   println(user)}

*Scala会默认生成name(),name_=(.)和构造函数() 
*name()对应java中的getName()方法 
*name_=()对应java中的setName()方法 
*定义的是公有成员,但生成的字节码中是以私有方式实现的,生成的getter,setter方法是公有的 
*定义私有成员,其getter,setter也是私有的 
*如果将成员域定义为private[this],则不会生成getter,setter方法 
*private[this]只能由该类创建的对象本身能访问到,因此它定义的类成员也称为对象私有成员 
*如需要像java中一样自动产生getter,setter方法,需要引用scala.reflect.BeanProperty,采用注解的方式修饰变量 
*当主构造器的参数不用var或val修饰的时候,参数会生成类的私有val成员,并且不会产生getter和setter方法 


自定义getter和setter方法 

def name=name  def name_=(name:String){      this.name=name}


定义类的同时定义主构造器 

class User(val name:String,val age:Int){  override def toString: String = name +":"+ age}object Test extends App{  val user = new User("caspar",27)  println(user)}


主构建器带默认参数

class User(val name:String="",val age:Int=28){...} 


主构造器中参数带访问控制符 

class User(val name:String,private val age:Int=19){  override def toString: String = name +":"+ age  println("age"+age)}object Test extends App{  val user = new User("caspar",12)  //user.age //error inaccessible  println(user)}


类名后面紧跟private关键字可以将主构建器设为私有,不允许外部使用

class User private(var name:String,var age:Int){...} 


*如果禁用掉了主构建器,则必须使用辅助构造函数来创建对象 
*辅助构建器的名称为this,java中的辅助构造函数与类名相同,这常常会导致修改类名时出现不少问题,scala语言避免了这样的问题 
*调用辅助构造函数时,必须先调用主构造函数或其它已经定义好的构造函数 

只有辅助构造函数的类

class User(){  //类成员  private var name:String=null  private var age:Int=18  private var sex:Int=0  //辅助构造器  def this(name:String){    this()    this.name=name  }  def this(name:String,age:Int){    this(name)    this.age=age  }  def this(name:String,age:Int,sex:Int){    this(name,age)    this.sex=sex  }  override def toString: String = name+":"+age+":"+sex}object Test extends App{  val user1 = new User("caspar",12,1)  val user2 = new User("caspar",12)  val user3 = new User("caspar")  println(user1)  println(user2)  println(user3)}

带有主构建函数和辅助构建函数的类

class User(var name:String,var age:Int){  //类成员  private var sex:Int=0  def this(name:String,age:Int,sex:Int){    this(name,age)    this.sex=sex  }  override def toString: String = name +":"+age+":"+sex}object Test extends App{  val user1 = new User("caspar",12,1)  val user2 = new User("caspar",12)  println(user1)  println(user2)}


Abstract类

抽象类是一种不能被实例化的类,抽象类中包括了未实现的抽象方法,这些方法由子类去扩展自己的实现 
子类继承抽象类,抽象类中的方法必须有实现,否则子类也必须定义为抽象类 
抽象类也可以直接new一个匿名类对象,在该匿名类对象中对方法加以实现 

scala中的抽象类定义 

abstract class User {  def login:Unit}

除抽象方法外,抽象类中还可以有抽象字段: 

abstract class User {  def login:Unit  //抽象字段,一般类中定义字段必须初始化,而抽象类中则没有这要求  var age:Int  var name:String}//通过主构造器对name参数进行了初始化class Waiter(var name:String) extends User{  override def login: Unit = {    println("waiter "+name+" is logined")  }  override var age: Int = _}class Customer extends User{  //对父类中的方法进行实现,注意这里面可以不加override关键字  def login: Unit = {    println("Customer "+name+" is logined")  }  override var age: Int = 0  override var name: String = null}object Test extends App{  val user = new Customer()  user.name = "caspar"  user.login  val waiter = new Waiter("caspar")  waiter.login    //下面的代码定义了一个匿名类,并且进行了实例化  //直接new User,后面跟的是类的内容  //User是一个抽象类,它是不能被实例化的  //这里能够直接new操作是因为我们扩展了User类,这个类是匿名的,只能使用一次  var somebody = new User {    override def login: Unit = {      println("User "+name+" is logined")    }    override var name: String = _    override var age: Int = _  }  somebody.name="caspar"  somebody.login }

伴生对象与伴生类

class User {  def print:Unit ={    UserTest.num+=1    println(      UserTest.num+".\tname:"+name+"\tage:"+age )  }  var age:Int = _  var name:String = _}object UserTest extends App{  var num = 0  var user = new User()  user.name="caspar"  user.age=29  user.print  user.print  user.print}

object UserTest被称为class User的伴生对象,而class User被称为object Usertest的伴生类 

内部类

*内部类可以像类的其它成员一样访问外部类的私有成员 *外部类不能访问内部类的成员域,但内部类可以直接访问外部类成员域,即使private私有的

class User {  def print:Unit ={    println(      "name:"+name+"\tage:"+age )  }  var name:String = _  private var pwd:String = "password"  var age:Int=18  private[this] def info: String = "name:"+name+"\tage:"+age  class SocialAccount(var google:String){    var qq:String = _    var email:String = _    var facebook:String= _    //内部的类可以直接访问外部类的成员变量和成员方法,即使是private    override def toString: String = info+"\tpwd:"+pwd+"\tqq:"+qq+"\temail:"+email+"\tfacebook:"+facebook+"\tgoogle"+google    def print:Unit ={      println(this)    }  }}object Test extends App{  val user = new User  user.name= "caspar"  user.age=19  user.print  var a = new user.SocialAccount("google account")  a.facebook="facebook account"  a.qq="qq account"  a.email="test@test.com"  a.print}

类的继承extends及多态

*“多态”(Polymorphic)也叫“动态绑定”(Dynamic Binding)、“迟绑定”(Late Binding),指“在执行期间(而非编译期间)判断所引用对象的实际类型,根据其实际类型调用其相应的方法。”即指子类的引用可以赋给父类,程序在运行时根据实际类型调用对应的方法 
*override方法重写指的是当子类继承父类的时候,子类重写父类的方法,方法重写是实现多态和动态绑定的关键 
*scala中的方法重写同java一样,也是利用override关键字标识重写父类的算法 

类的继承

class User {  def print:Unit ={    println(      "name:"+name+"\tage:"+age )  }  var name:String = _  private var pwd:String = "password"  protected var phone:String = "12345678900"  var age:Int=18}class Customer(var vip:Boolean) extends User{  //子类可以访问父类的protected属性和方法,但不能访问private属性和方法  //重写了自己的实现  override def print: Unit = println("Customer name:"+name+"\tCustomer age:"+age+"\tvip:"+vip+"\tphone:"+phone)}object Test extends App{  //User类的引用可以指向User类的任何子类  val c:User = new Customer(false)  c.name= "caspar"  c.age=19  //c.phone =10  这里不能访问到protected phone  c.print //程序会根据实际类型调用对应的不同子类中的print()方法}

构造函数执行顺序

class User {  println("第一行输出:User.....")  def print:Unit ={    println(      "name:"+name+"\tage:"+age )  }  var name:String = _  private var pwd:String = "password"  protected var phone:String = "12345678900"  var age:Int=18}class Customer(var vip:Boolean) extends User{  var qq:String = _  var email:String = _  def this(vip:Boolean,qq:String,email:String){    this(vip)    this.qq = qq    this.email = email    println("第二行输出:Customer this(...)...")  }  println("第三行输出:Customer....")  //子类可以访问父类的protected属性和方法,但不能访问private属性和方法  override def print: Unit = println("第四行输出:Customer name:"+name+"\tCustomer age:"+age+"\tvip:"+vip+"\tphone:"+phone)}object Test extends App{  val c:User = new Customer(false,"q1234677","email@test.com")  c.name= "caspar"  c.age=19  //c.phone =10  这里不能访问到protected phone  c.print}

Trait

Scala和Java语言一样,采用了很强的限制策略,避免了多种继承的问题。在java语言中,只允许继承一个超类,该类可以实现多个接口,但java接口有其自身的局限性:接口中只能包括抽象方法,不能包含字段、具体方法。 
Scala语言利用Trait解决了该问题,在scala的trait中,它不但可以包括抽象方法还可以包含字段和具体方法。 
使用with实现Trait接口 
Trait中可以带有具体字段和具体方法的实现 
trait有自己的构造器,它是无参构造器,不能定义trait带参数的构造器 

trait的构造顺序 
1. 如果有超类,则先调用超类的构造器 
2. 如果有父trait,它会按照继承层次先调用父trait的构造器 
2. 如果有多个父trait,则按顺序从左到右执行 
3. 所有父类构造器和父trait被构造完之后,才会构造本类 

trait User {  //定义一个抽象方法,注意不需要加abstract  def login(id:String):String  def add(o:Any):Boolean  def update(o:Any):Int  def query(id:String):List[Any]}trait Vip {  def info(vip:Boolean):Boolean  //带有具体字段  private var num = 0    //带有具体方法和属性的实现  def upgrade={    num+=1    println("升级成"+num+"号vip 会员")  }}class Customer extends User with Vip{  override def login(id: String)=id  override def add(o: Any): Boolean = {    if(o==null) false    else true  }  override def update(o: Any): Int = {    if(o==null) 0    else 1  }  override def query(id: String): List[Any] = List(id,"aaa","bbb")  override def info(vip: Boolean): Boolean = vip}object Test extends App{  val u = new Customer  Predef println u.login("userid 001")  println(u.add("add user"))  println(u.update("update user"))  println((u query "userid 001").mkString(","))  println("vip:"+u.info(false))  u.upgrade  u.upgrade}

自身类型(=>)

用法一

class OuterClass {     outer => //定义了一个外部类别名    val v1 = "here"    class InnerClass {        // 用outer表示外部类,相当于OuterClass.this        println(outer.v1)     }}

用法一

trait User {  //定义一个抽象方法,注意不需要加abstract  def login(id:String):String}class Customer{  //self:User => 要求Customer在实例化时或定义Customer的子类时  //必须混入指定的User trait,这个User类型也可以指定为当前类型  self:User=>}//类Test扩展Customer的时候必须混入trait User//否则的话会报错object Test extends Customer with User{  override def login(id: String): String = id+" login..."  def main(args: Array[String]): Unit = {    println(login("001"))  }}

包对象

包对象主要用于将常量、工具函数,使用时直接通过包名引用 
包对象的定义

package com.scala.test

利用package关键字定义单例对象

package object Id{  var id=0  def autoIncrementId:Int={    id+=1    id  }}object Test extends App{  println(Id.autoIncrementId)  println(Id.autoIncrementId)  println(Id.autoIncrementId)}

访问控制

在java语言中,主要通过public、private、protected及默认控制来实现包中类成员的访问控制,当定义一个类时,如果类成员不加任何访问控制符时,表示该类成员在定义该类的包中可见。在scala中没有public关键字,仅有private 和 protected访问控制符,当一个类成员不加private和protected时,它的访问权限就是public。下面逐个进行讲解:

private 成员

private成员同java是一样的,所有带该关键字修饰的成员仅能在定义它的类或对象中使用,在外部是不可见的

protected 成员

在java语言中,protected成员不但可以被该类及其子类访问,也可以被同一个包中的其它类使用,但在scala中,protected成员只能被该类及其子类访问

无修饰符成员

无修饰符的成员同java 的public,可以在任何位置进行访问

范围保护

在scala中提供了更为灵活的访问控制方法,private、protected除了可以直接修饰成员外,还可以以private[X]、protected[X]的方式进行更为灵活的访问控制,这种访问控制的意思是可以将private、protected限定到X,X可以是包、类,还可以是单例对象

private[this],限定只有该类的对象才能访问,称这种成员为对象私有成员

private,定义的类及伴生对象可以访问

访问规则表

修饰符访问范围无任何修饰符任何地方都可以使用private[scala]在定义的类中可以访问,在scala包及子包中可以访问private[this]只能在定义的类中访问,即使伴生对象也不能访问团private在定义的的类及伴生对象中可以访问,其它地方不能访问protected[scala]在定义的类及子类中可以访问,在scala包及子包中可以访问protected[this]只能在定义的类及子类中访问,即使伴生对象也不能访问protected在定义的类及子类中访问,伴生对象可以访问,其它地方不能访问

import

隐式引入

可以直接使用包中或对象中所有的类和方法,称这种引入会隐式引入 
scala默认导入以几个包: 
import java.lang_ 
import scala._ 
import Predef._ 

重命名

scala中允许对引入的类或方法进行重命名,如果我们需要在程序中同时使用java.util.HashMap及scala.collection.mutable.HashMap时,可以利用重命名的方法消除命名冲突的问题 
将java.util.HashMap重命名为JavaHashMap 
import java.util.{ HashMap ⇒ JavaHashMap } 
import scala.collection.mutable.HashMap 

类隐藏

通过HashMap⇒ _,这样类便被隐藏起来了 
import java.util.{HashMap⇒ _,_} 
import scala.collection.mutable.HashMap 

0 0
原创粉丝点击