学习笔记—scala基础II

来源:互联网 发布:班级管理系统数据库 编辑:程序博客网 时间:2024/05/22 12:29

  1. //定义类
  2. class helloworld{
  3. private var name="Tom"
  4. def say(){ print("hello,"+ name)}
  5. def getname()=name
  6. }
  7. //创建类的对象
  8. val aa=new helloworld
  9. //调用方法
  10. aa.say()
  11. print(aa.getname()) //可以不加(),如果定义方法是不带括号,调用时也不能带()
  12. //

getter和setter 
定义不带private的var字段,scala生成面向JVM的类时,会定义为private的var字段,但是getter和setter是public 
定义private的var字段,生成private的getter和setter 
(无论字段是不是private修饰的,字段都会是private的,区别只是在getter和setter) 
如果定义val字段,只会生成getter 
如果不想生成getter和setter方法,可以将字段声明为private[this]

  1. class person{
  2. var age =0
  3. }
  4. //scala 中getter 和setter 方法分别叫age和age_
  5. //自定义getter,setter方法
  6. class Student{
  7. private var myName="tom"
  8. //自定义getter方法
  9. def name="hello,"+myName
  10. //自定义setter方法,注意签名、=、参数三者之间不能有空格
  11. def name_=(newName:String){
  12. println("you do not edite your name!")
  13. }
  14. }
  15. object GetterAndSetter {
  16. def main(args: Array[String]): Unit = {
  17. val aa=new Student()
  18. println(aa.name)
  19. aa.name_=("jack")
  20. }
  21. }

仅暴露字段的getter方法

  1. class student{
  2. private var myName="Tom"
  3. def updataname(newName:String){
  4. if(newName=="Amy") myName=newName
  5. else print("NO")
  6. }
  7. def name="you name is "+myName
  8. }

private[this]的使用

  1. class student{
  2. private[this] var myage=0
  3. def age_=(nameValue:Int){
  4. if (newValue>0)myage = newValue
  5. else print("No")
  6. }
  7. def age=myage
  8. def older(s:Student)={
  9. myage>s.myage //报错,[this]
  10. }
  11. }

辅助constructor(构造函数)

  1. //可以给类定义多个辅助constructor,辅助constructor之间可以互相调用
  2. class Stu{
  3. private var name="default"
  4. private var age=0
  5. //第一个辅助构造器
  6. def this(name:String){
  7. this() //调用主构造器
  8. this.name=name
  9. }
  10. //第二个辅助构造器
  11. def this(name:String,age:Int){
  12. this(name) //调用第一个辅助构造器
  13. this.age=age
  14. }
  15. def sayHello=println(name+" "+age)
  16. }
  17. object ConstructorDemo {
  18. def main(args: Array[String]): Unit = {
  19. val stu1=new Stu //调用默认的主构造器
  20. stu1.sayHello
  21. val stu2=new Stu("张三") //调用第一个辅助构造器
  22. stu2.sayHello
  23. val stu3=new Stu("李四",20) //调用第二个辅助构造器
  24. stu3.sayHello
  25. }
  26. }

主constructor 
主constructor是与类名放在一起的,类中没有定义任何方法或者代码块之中的代码,就是主constructor的代码

  1. class Per(val name:String,val age:Int){
  2. println("my name is "+name+",my age is "+age)
  3. println("hello,main constructor!")
  4. }
  5. object MainConstructor {
  6. def main(args: Array[String]): Unit = {
  7. val per=new Per("张三",20)
  8. }
  9. }

对象

object

相当于class的单个实例,第一次调用object的是后会执行object的constructor(只会在第一次调用时执行一次) 
但是object不能定义接受参数的constructor

伴生对象

如果有一个class还有一个与class同名的object,那么这个object是class的伴生对象,class是object的伴生类 
两者必须在同一个.scala文件中() 
最大特点就是可以互相访问private字段

  1. class Account{
  2. // val array=Array()
  3. //伴生类中的私有字段
  4. private var num=10
  5. //通过Account.num2调用伴生对象中的私有字段num2
  6. def getNum2=println(Account.num2)
  7. //通过Account.getResult调用伴生对象中的私有函数
  8. num=Account.getResult
  9. def getInfo=println(num)
  10. }
  11. //伴生对象
  12. object Account {
  13. //伴生对象中的私有字段
  14. private var num2=20
  15. //伴生对象中的私有函数
  16. private def getResult={
  17. num2+=10
  18. num2
  19. }
  20. //创建apply()方法,用于创建伴生类的对象
  21. def apply()={
  22. println("这是伴生对象中的apply方法!")
  23. new Account
  24. }
  25. def main(args: Array[String]): Unit = {
  26. val account=Account()//调用的是伴生对象中的apply方法
  27. account.getInfo
  28. // val account=new Account
  29. //在伴生对象中,通过伴生类的对象访问类中的私有字段
  30. // println(account.num)
  31. }
  32. }
  33. //类的伴生对象可以被访问但不在作用域中
  34. //Account类必须通过Account.newUniqueNumber()类调用伴生对象的方法
  • apply方法 
    通常在伴生对象中实现apply方法,并在其中实现构造伴生类的对象功能 
    在创建伴生类的对象是使用Class()的方式,隐式的调用伴生对象的apply方法
  1. class person(val name:String )
  2. object person{
  3. def apply(name:String)=new persom(name)
  4. }
  5. //伴生对象
  6. object Account {
  7. //伴生对象中的私有字段
  8. private var num2=20
  9. //伴生对象中的私有函数
  10. private def getResult={
  11. num2+=10
  12. num2
  13. }
  14. //创建apply()方法,用于创建伴生类的对象
  15. def apply()={
  16. println("这是伴生对象中的apply方法!")
  17. new Account
  18. }
  19. def main(args: Array[String]): Unit = {
  20. val account=Account()//调用的是伴生对象中的apply方法
  21. account.getInfo
  22. // val account=new Account
  23. //在伴生对象中,通过伴生类的对象访问类中的私有字段
  24. // println(account.num)
  25. }
  26. }
  • 用object来实现枚举功能 
    scala中没有类似于java中enum的枚举特性 
    object继承Enumeration,并调用Value放发来初始化枚举值
  1. val aa extends Enumeration{
  2. val spring,summer,autumn,winter=Value
  3. }
  4. object aa extends Enumeration{
  5. val spring = Value(0,"spring")
  6. val summer = Value(1,"summer")
  7. val autumn = Value(2,"autumn")
  8. val winter = Value(3,"winter")
  9. }
  10. aa(0)
  11. aa.withName("winter")
  12. //使用枚举object.values可以遍历枚举值
  13. for (ele<-aa.Value)printele
  • mian方法 
    scala的main方法必须定义在object中 
    除了自己实现mian方法外,还可以继承App trait,将要运行的代码自己而作为object的constructor代码,而且用args可以接受传入的参数
  • object 继承抽象类 
    object的功能和class类似,除了不能定义接受参数的constructor 
    object可以继承抽象类,并覆盖抽象类的方法
  1. abstract class Hello (var message:String){
  2. def say(name:String):Unit
  3. }
  4. object Hello1 extends Hello("aa"){
  5. override def say(name:String)={
  6. println(message+" "+name)
  7. }
  8. }

继承

使用关键字extends 
继承代表子类可以继承父类的字段和方法,子类可以覆盖父类的字段和方法, 
如果父类用final 修饰,是无法继承的,字段或方法用final修饰,字段和方法是无法被覆盖的。 
如果子类要覆盖一个父类中的飞抽象方法,必须使用override 
在覆盖父类方法后,在子类中调用父类被覆盖哦的方法,使用super,显式的指定要调用父类的方法

  1. class person{
  2. private var name="leo"
  3. def getName=name
  4. }
  5. class student extends person{
  6. private var score="92"
  7. def getScore=score
  8. override def getName="hi,i am"+super.getName
  9. }

子类可以覆盖父类的val字段,只要使用override关键字即可

  • isInstanceOf 和asInstanceOf 
    isInstanceOf :判断对象是否是指定类的对象 
    asInstanceOf:将对象转换为指定类型 
    如果对象是null,则isInstanceOf一定返回false,asInstanceOf一定返回null 
    如果没有进行判断直接转换类型,可能会抛出异常
  1. if(p.isInstanceOf[Studnet]) s=p.asInstanceOf[Studnet]

isInstanceOf不能进行精确的判断 
对象.getClass可以精确的获取对象的类,classOf[类] 可以精确的获取类,然后使用==连接即可

  1. class person
  2. class studnet extends person
  3. val p: person= new studnet
  4. p.isInstanceOf[person]
  5. p.isInstanceOf[studnet]
  6. p.getClass==classOf[person]
  7. p.getClass==classOf[student]
  • 模式匹配 
    功能上与isInstanceOf一样,主要是判断是该类以及该类的子类对象即可,是不精确判断
  1. class person
  2. class studnet extends person
  3. val p: person= new studnet
  4. p match{
  5. case per:person=>println("asdad")
  6. case _ => println("NO") //注意case与下划线之间有一个空格
  7. }
  • protectd 关键字 
    使用protectd 修饰字段或方法,子类就不需要super关键字就能直接访问字段和方法了 
    protectd[this] ,只能在当前子类中党文父类的字段和方法
  • 调用父类的constructor 
    每个类都有一个主constructor和多个辅助constructor 
    每个辅助constructor的第一行必须是调用其他辅助constructor或者是主constructor,所以子类的辅助constructor一定不能直接调用父类的constructor的 
    只能在子类的主constructor中调用父类的constructor
  1. class person(val name:String ,val age:Int)
  2. class student(name:String,age:Int,var score:Double) extends person(name,age){
  3. def this(name:String){
  4. this(name,0,0)
  5. }
  6. def this(age:Int){
  7. this("tom",age,0)
  8. }
  9. }
  • 抽象类 
    父类中的那些不给出具体实现的方法,只有方法签名,称为抽象方法 
    如果类中有抽象方法,,类必须使用abstract声明为抽象类,是不能实例化的 
    在子类中覆盖抽象类的抽象方法时,不需要使用override关键字
  1. abstract class person(val name:String)
  2. class student(name:String) extends person(name){
  3. def say:Unit=println("hello"+name)
  4. }
  • 抽象字段 
    在父类中定义了字段,没有给出初始值,为抽象字段 
    scala会为val 和var类型的字段生成对应的个getter和setter方法,子类必须覆盖字段以定义自己的具体字段,不用override关键字

trait特质

可以将trait作为借口来使用,在trait中定义抽象方法,和抽象类中的抽象方法一样,只要不给出具体的实现即可 
类可以使用extends继承trait,继承后必须实现其中的抽象方法,实现时不需要override 
scala不支持对类进行多继承,但支持多重继承trait,还用with关键字

  1. //将trait作为接口使用
  2. trait hello{
  3. def say(name:String)
  4. }
  5. traitmakefriend{
  6. def makefriends(p:person)
  7. }
  8. class person (val nameString)extends hello with makefriends with Serializable{
  9. def say(name:String)=println("hello"+name)
  10. def makefriend(p:person)=print(name+" "+p.name)
  11. }
  • trait定义具体方法
  1. trait logger{
  2. def log(message:String)=println(message)
  3. }
  • trait中定义具体字段 
    trait中可以定义具体字段,此时继承trait的类就自动获得了trait中的字段 
    与继承class获取的字段是不同的,实际是定义在父类中的,而继承trait获取的字段是直接添加到类中的
  1. //实例混入trait
  2. traid Logged{
  3. def log(msg:String)
  4. }
  5. trait MyLogger extends Logged{
  6. override def log(msg:String){
  7. println("log:"+msg)
  8. }
  9. }
  10. class person(val name:String) extends Logged{
  11. def say("hi-----I am"+ name);
  12. log("sayHellomydear")
  13. }
  14. val aa = new person("sam")
  15. aa.say
  16. val bb = new person("Tony") with MyLogger
  17. bb.say

调用链问题总结

  1. 调用链必须是类继承多个trait
  2. 多个trait中必须包含同一个方法,并多个trait有一个共同的父trait
  3. 调用的多个trait的同一个方法中,最后的语句必须是super.方法名,通过这种形式trait调用链中下一个trait的方法
  4. 满足以上条件才能构成trait调用链,在调用链中按照从右到左的顺序依次调用一个方法
  • 混合使用trait的具体方法和抽象方法 
    可以让抽象方法方法哦继承trait的类中实现,这就是模板设计模式

  • trait的构造机制

  1. 父类的构造函数执行
  2. trait的构造代码执行,多个trait从右放左执行
  3. 构造trait是会先构造父类trait,若多个trait继承同一个父类,父类只会构造一次
  4. 所有的trait构造完毕后,子类的构造函数执行
1 0
原创粉丝点击