Scala学习二-面向对象

2020-10-26 15:35:44 浏览数 (1)

在Scala中创建类和对象

代码语言:javascript复制
object OopDemo{
 //创建类
 class Monkey(){}
 //创建main方法
  def main(args: Array[String]): Unit = {
      //创建Monkey对象
      val m = new Monkey()
      //进行输出
      println(m)
  }  
}

省略条件

代码语言:javascript复制
1.如果类是空的,没有成员变量,可以省略{ }
2.如果构造器的参数为空,可以省略( )

因此上面可以简写为:

代码语言:javascript复制
object OopDemo{
    //创建类,没有成员变量,根据条件1省略{ }
    class Monkey
    //创建main方法
    def main(args: Array[String]): Unit = {
        //创建Monkey对象,由于是空参对象,因此根据条件2省略()
        val m = new Monkey
        //进行输出
        println(m)
    }
}

带成员变量类对象

代码语言:javascript复制
object OopDemo{
    //创建monkey类
    class Monkey{
       //定义成员变量
        var name = ""
        var age = 0
    }
    //创建main方法,25的程序猿
    def main(args: Array[String]): Unit = {
        //创建Monekey对象
        //val m = new monkey()
        val m = new Monkey
        //设置属性值
        m.name = "程序员"
        m.age = 25
        //进行输出
        println(m.name "----------" m.age)
    }
}

使用下划线进行成员变量初始化

适用于var变量,对于val不适用,注意如果使用下划线进行初始化,此时必须提供数据类型,这样就可以进行自动推断赋初始值

代码语言:javascript复制
object OopDemo{
  //创建Monkey类,带成员变量
    class Monkey{
        var name:String = _
        var age:Int = _
    }
    
   //创建main方法,25的程序猿
    def main(args:Array[String]): Unit = {
        //创建monkey对象,设置属性值
        val m = new Monkey
        m.name = "程序员"
        m.age = 25
        //进行输出
        println(m.name "-------" m.age)
    }
}

定义和访问成员方法

代码语言:javascript复制
def 方法名(参数1:数据类型,参数2: 数据类型): [return type] = {
    //方法体
}

注:返回数据类型可以不写

代码语言:javascript复制
object  OopDemo{
    //创建Monkey类
    class Monkey{
        //定义成员变量
        var name:String = _
        var age = 0
        
        //定义成员方法eatBanana,喜欢吃香蕉
        def eatBanana(msg: String) = {
            println(msg)
        }
    }
    
    //创建main方法,一个25的喜欢吃香蕉的程序猿
    def main(args: Array[String]): Unit = {
       //创建monkey对象
        val m = new Monkey
        m.name = "程序员"
        m.age = 25
        //进行输出
        println(m.name "------------" m.age)
        //调用成员方法eatBanana
        eatBanana("喜欢吃香蕉")
    }
}

访问权限修饰符

scala的权限修饰符:private,private[this],protected,默认四种,没有public修饰符

我们使用private修饰成员变量

代码语言:javascript复制
object OopDemo{
  //创建monkey
  class Monkey{
      //定义成员变量,使用private
      private var name = ""
      private var age = 0
      
      //定义成员方法
      def getName() = name
      //设置姓名
      def setName(name: String) = this.name = name
      
      //获取年龄
      def getAge() = age
      //设置年龄
      def setAge(age: Int) = this.age = age
      
      //定义方法
      def eatBanana() = println("喜欢吃香蕉")
      }
  }
    
  def main(args: Array[String]): Unit = {
      //创建monkey对象
      val m = new Monkey
      m.setName("程序员")
      m.setAge(25)
      //进行输出
      println(m.getName()   "------"   m.getAge())
  }
}

主构造器

代码语言:javascript复制
class 类名(var/val 参数名:类型 = 默认值, var/val 参数名: 类型 = 默认值){
    //构造代码块
}

如:设置构造器

代码语言:javascript复制
object OopDemo{
    //创建monkey类,主构造器
    class Monkey(val name: String = "程序员", val age: Int = 25){
        println("调用了主构造器")
    }
    
    //创建main方法
    def main(args: Array[String]): Unit = {
        //创建空对象
        val m = new Monkey
        println(s"m: ${p.name}.....${p.age}")
        
        //创建对象,对应
        val m1 = new Monkey("程序员",25)
        println(s"m1: ${m1.name}.....${m1.age}}")
        
        //创建对象,仅传入年龄
        val m2 = new Monkey(age = 28)
        println("m2: ${m2.name}....${m2.age}")
    }
}

辅助构造器

辅助构造器的默认名字都是this,且不能修改,辅助构造器的第一行代码,必须要调用主构造器或者其他辅助构造器

代码语言:javascript复制
def this(参数名: 类型,参数名: 类型){
  //第一行需要调用主构造器或者其他构造器
  //构造器代码  
}
代码语言:javascript复制
object OopDemo{
    //定义构造函数
    class Monekey(var name: String, var hobbby: String){
       //定义辅助构造方法
        def this(arr: Arrray[String]){
            this(arr(0),arr(1))
        }
    }
   //创建main函数
    def main(args: Array[String]): Unit = {
       //创建对象
        var m = new Monkey(Array("程序员","喜欢吃香蕉"))
        //进行结果
        println(m.name "--------" m.hobbby)
    }
}

单例对象

代码语言:javascript复制
object 单例对象名{ } //定义一个单例对象
代码语言:javascript复制
object OopDemo{
 //创建单例对象
 object Monkey{
     //定义一个方法
     def monkeyLike() = monkeyHobby("monkey爱吃香蕉")
     }
    //创建main方法
    def main(args: Array[String]): Unit = {
        //调用单例对象的成员方法
        Monkey.monkeyLike()
    }
 }
}

定义程序主入口

scala和java一样,如果要运行一个程序,必须有一个main方法。在java中main方法是静态的,而在scala中没有静态方法,所以在scala中,main方法必须放在一个单例对象中。

main方法
代码语言:javascript复制
def main(args:Array[String]):Unit = {
 //方法体
}
继承App特质

创建一个object,继承自App特质(Trait),然后将需要编写在main方法中的代码,写在object的构造方法体内

代码语言:javascript复制
object 单例对象名 extends App{
   //方法体
}

在kafka中,我们可以看到程序的主入口是kafka.scala

代码语言:javascript复制
//主入口
def main(args: Array[String]): Unit = {
    try {
      //获取配置信息服务端  
      val serverProps = getPropsFromArgs(args)
      val kafkaServerStartable = KafkaServerStartable.fromProps(serverProps)

      try {
        if (!OperatingSystem.IS_WINDOWS && !Java.isIbmJdk)
          //注册日志信号处理器
          new LoggingSignalHandler().register()
      } catch {
        case e: ReflectiveOperationException =>
          warn("Failed to register optional signal handler that logs a message when the process is terminated "  
            s"by a signal. Reason for registration failure is: $e", e)
      }

      // attach shutdown handler to catch terminating signals as well as normal termination
      //添加关闭钩子函数  
      Runtime.getRuntime().addShutdownHook(new Thread("kafka-shutdown-hook") {
        override def run(): Unit = kafkaServerStartable.shutdown()
      })

      //kafkaServer端启动 重要
      kafkaServerStartable.startup()
      //等待关闭,这里使用了countDownLatch同步并发容器  
      kafkaServerStartable.awaitShutdown()
    }
    catch {
      case e: Throwable =>
        fatal("Exiting Kafka due to fatal exception", e)
        Exit.exit(1)
    }
    //进行退出 终端
    Exit.exit(0)
  }
}

伴生对象

一个class和obect具有相同的名字,这个object称为伴生对象,这个class称为伴生类

注意:

代码语言:javascript复制
伴生对象必须要和伴生类一样的名字
伴生对象和伴生类在同一个scala源文件中
伴生对象和伴生类可以相互访问private属性
代码语言:javascript复制
object OopDemo{
  //定义类Monkey
  class Monkey{
     //定义monkey的方法eat()方法,猴子爱吃香蕉
      def eat()= println(s"猴子爱吃${eat.foodName}")
  }
    //定义伴生对象,用来保存食物香蕉,注意这个对象中的成员是静态变量
    object Monkey{
        private var foodName = "banana"
    }
    //创建main方法
    def main(args: Array[String]): Unit = {
        //创建Monkey读写
        var m = new Monkey
        //调用Monkey中的eat方法
        m.eat()
    }
}

private[this]访问权限

如果某个成员的权限设置为private[this],表示只能在当前类中访问。伴生对象也不可以访问

代码语言:javascript复制
object OopDemo{
    //创建一个Monkey类,属性为name,这里需要去掉private[this],否者会报错
    class Monkey(private[this] var name: String)
    
    //定义Monkey类的伴生对象
    object Monkey{
        //定义monkeyName方法
        def monkeyName(m:Monkey) = println(m.name)
    }
    //创建main方法
    def main(args: Array[String]) = {
        //创建Monkey对象
        val m = new Monkey("程序员")
        //进行输出
        Monkey.monkeyName(m)
    }
}

apply方法

在Scala中,支持创建对象的时候,可以不写new的操作,要想实现不写new操作,就需要通道伴生对象的appky方法来实现

定义apply方法

代码语言:javascript复制
object 伴生对象名{
    def apply(参数名:参数类型, 参数名: 参数类型...) =  new 类(...)
}

创建对象

代码语言:javascript复制
val 对象名 = 伴生对象名(参数1,参数2....)
代码语言:javascript复制
object OopDemo{
  //创建monkey类,属性名
    calss Monkey(var name: String = "",var age: Int = 0)
  //创建Moneky类的伴生对象
    object Monkey{
       //定义apply方法,创建对象Monkey对象的时候可以不写new
        def apply(name: String, age: Int) = new Monkey(name, age)
  }
  //创建main方法
    def main(args: Array[String]): Unit = {
        //创建Monkey对象,28的程序猿
        val m = Monkey("程序员",28)
        //进行输出
        println(m.name "---------" m.age)
    }
}

继承

代码语言:javascript复制
class/object A类 extends B类 {
    ...
}
继承

Monkey分为程序猿和金丝猴

代码语言:javascript复制
object OopDemo{
  //创建Monkey类
    class Monkey{
        var name = " "
        var age = 0
        
        def eat()=println("monkey爱吃香蕉")
    }
    
    //定义金丝猴
    class GoldenMonkey extends Monkey
    
    //定义程序猿
    class ProgramMonkey extends Monkey
    
    //创建main方法
    def main(args: Array[String]): Unit = {
       //创建金丝猴对象,喜欢吃香蕉的金丝猴
        val g = new GoldenMonkey
        g.name = "金丝猴"
        g.age = 2
        println(g.name   "----------"   g.age)
        g.ear()
        
        //创建程序猿,一个28爱吃香蕉的程序猿
        val p = new ProgramMonkey
        p.name = "程序猿"
        p.age = 28
        println(p.name   "----------"   p.age)
        p.eat()
    }
}
单对象继承

在Scala中,单例对象也可以继承类的

代码语言:javascript复制
object OopDemo{
 //创建monkey类
  class Monkey{
      var name =" "
      
      def eat() = println("喜欢吃芒果")
  }  
  //定义单例对象programMonkey
    object ProgramMonkey extends Monkey
  
 //创建main方法,一个喜欢吃芒果的程序猿
    def main(args: Array[String]): Unit = {
       ProgramMonkey.name = "程序猿"
       println(ProgramMonkey.name)
       ProgramMonkey.eat()
    }
}
方法重写

子类中出现和父类一模一样的方法时, 称为方法重写. Scala代码中可以在子类中使用override来重写父类的成员,也可以使用super来引用父类的成员.可以使用override来重新一个val字段。

代码语言:javascript复制
Object OopDemo{
  //定义父类Monkey
    class Monkey{
        var name = "猴子"
        val age = 2
        
        def eat() = println("吃香蕉")
    }
  
  //定义子类ProgramMonkey
    class ProgramMonkey extends Monkey{
        //使用override重写方法和变量
        override val age = 28
        override def eat() = {
            super.eat()
            println("同样喜欢吃芒果")
        }
    }
    
    //main方法,喜欢吃香蕉和芒果的程序猿
    def main(args: Array[String]): Unit = {
        //创建ProgramMonkey对象
        val p = new ProgramMonkey
        println(p.name   "--------"   p.age)
        p.eat()
    }
}

类型判断

有两种方式:

代码语言:javascript复制
1.isInstanceOf:判断对象是否为指定类的对象
  asInstanceOf:将对象转换为指定类型
  
2.getClass/classOf:如果要求精确地判断出对象的类型就是指定的数据类型,那么就只能使用 getClass 和 classOf 来实现.
isInstanceOf/asInstanceOf
代码语言:javascript复制
object OopDemo{
    //创建Monkey类
    class Monkey
  
    //创建一个ProgramMonkey
    class ProgramMonkey extends Monkey{
        def eat() = println("吃香蕉")
    }
    //main方法
    def main(args: Array[String]): Unit = {
        //通过多态创建programMonkey对象
        val p: Monkey = new ProgramMonkey
        //创建其是不是Monkey类型的对象,如果是,则将其转为Monkey类型的对象
        if(p.isInstanceOf[Monkey]){
        //调方法
        p.eat()
    }
  }
}

注意:isInstanceOf只能判断对象是否为指定类以及其子类的对象,而不能精确的判断出:对象就是指定类的对象。如果要求精确地判断出对象的类型就是指定的数据类型,那就只能使用getClass和classOf来实现

getClass和classOf
代码语言:javascript复制
getClass可以精确获取对象的类型
classOf[类名]可以精确获取数据类型
使用==操作符可以直接比较类型
代码语言:javascript复制
object OopDemo{
 //创建Monkey类
 class Monkey
 //创建一个ProgramMonkey类继承Monkey
  class ProgramMonkey extends Monkey
  
  def main(args: Array[String]): Unit = {
      //创建ProgramMonkey对象
      val p:ProgramMonkey = new ProgramMonkey
      //通过isInstanceOf关键字来判断是否是Monkey类型的对象 //true
      println(p.isInstanceOf[ProgramMonkey])
      //通过isInstanceOf关键字来判断是否是Monkey类型的对象 //false
      println(p.getClass == classOf[Monkey])
      //通过getClass,ClassOf判断其是否是ProgramMonkey
      println(p.getClass==classOf[ProgramMonkey]) //true
  }  
}

抽象类

代码语言:javascript复制
//定义抽象类
abstract class 抽象类名{
    //定义抽象字段
    val/var 抽象字段名:类型
    //定义抽象方法
    def 方法名(参数:参数类型,参数: 参数类型...):返回类型
}
代码语言:javascript复制
object OopDemo{
   //抽象类
    abstract class Monkey{
        val name: String
    }
    //定义ProgramMonkey继承Monkey,重新抽象字段
    class ProgramMonkey extends Monkey{
        override val name: String = "猴子"
    }
    //金丝猴类
    class GoldenMonkey extends Monkey{
        override val name: String = "金丝猴"
    }
    //程序猿
    class ProgramMonkey extends Monkey{
        override val 
    }
    
    //main方法
    def main(args: Array[String]): Unit = {
        //创建ProgramMonkey类的对象,输出
        val g = new GoldenMonkey
        println(g.name)
        //创建ProgramMonkey类的对象,进行输出
        val p = new ProgramMonkey
        println(p.name)
    }
}

匿名内部类

匿名内部类是继承了类的匿名的子类对象,它可以直接用来创建实例对象。

代码语言:javascript复制
new 类名(){
   //重新类中所有的抽象内容
}

使用场景

代码语言:javascript复制
1.(成员方法)仅调用一次的时候.
2.可以作为方法的参数进行传递.
代码语言:javascript复制
object OopDemo{
    //创建Monkey类,里面有一个抽象方法:eat()
    abstract class Monkey{
        def eat()
    }
    //定义一个show()方法,该方法传入一个Monkey类型的对象
    def show(m:Monkey) = m.eat()
    
    //main方法
    new Monkey{
        override def eat(): Unit = {
            println("喜欢吃香蕉,当堆成员方法仅调用一次的时候")
        }.eat()
    
    
    //匿名内部类可以作为方法的参数进行传递
    val m = new Monkey{
        override def eat(): Unit = println("可以作为方法的实际参数进行传递")
    }
     show(m)  
   }
}

特质

代码语言:javascript复制
1.特质可以提高代码的复用性
2.特质可以提高代码的扩展性和可维护性
3.类与特质之间是继承关系,只不过类与类之间只支持单继承,但是类与特质之间,既可以单继承,也可以多继承
4.Scala的特质中可以有普通字段, 抽象字段, 普通方法, 抽象方法.
代码语言:javascript复制
trait 特质名称{
    //普通字段
    //抽象字段
    
    //普通方法
    //抽象方法
}

继承特质

代码语言:javascript复制
class 类 extends 特质1 with 特质2{
    //重写抽象字段
    //重写抽象方法
}

注意:

代码语言:javascript复制
1.scala中不管是类还是特质,继承关系用的都是extends关键字
2.如果要继承多个特质(trait),则特质名之间使用with关键字隔开
代码语言:javascript复制
//trait入门之类继承单个特质
object OopDemo{
    //定义一个特质,抽象方法
    trait Logger{
        def log(msg:String)
    }
    //定义一个类,继承特质
    class ConsoleLogger extends Logger{
        override def log(msg: String): Unit = println(msg)
    }
    
    def main(args: Array[String]): Unit = {
        //调用类中的方法
        val cl = new ConsoleLogger
        c1.log("类继承单个特质")
    }
}

类继承多个trait

代码语言:javascript复制
//案例: 类继承多个trait
object OopDemo {
  //1. 定义一个特质: MessageSender, 表示发送信息.
  trait MessageSender {
    def send(msg:String)
  }
  //2. 定义一个特质: MessageReceiver, 表示接收信息.
  trait MessageReceiver {
    def receive()
  }
  //3. 定义一个类MessageWorker, 继承两个特质.
  class MessageWorker extends MessageSender with MessageReceiver {
    override def send(msg: String): Unit = println("发送消息: "   msg)

    override def receive(): Unit = println("消息已收到, 我很好, 谢谢!...")
  }

  //main方法, 作为程序的主入口
  def main(args: Array[String]): Unit = {
    //4. 调用类中的方法
    val mw = new MessageWorker
    mw.send("Hello, 你好啊!")
    mw.receive()
  }
}

0 人点赞