vlambda博客
学习文章列表

Scala学习二-面向对象

在Scala中创建类和对象

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

省略条件

1.如果类是空的,没有成员变量,可以省略{ }
2.如果构造器的参数为空,可以省略( )

因此上面可以简写为:

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

带成员变量类对象

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不适用,注意如果使用下划线进行初始化,此时必须提供数据类型,这样就可以进行自动推断赋初始值

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)
  }
}

定义和访问成员方法

def 方法名(参数1:数据类型,参数2: 数据类型): [return type] = {
   //方法体
}

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

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修饰成员变量

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())
}
}

主构造器

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

如:设置构造器

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,且不能修改,辅助构造器的第一行代码,必须要调用主构造器或者其他辅助构造器

def this(参数名: 类型,参数名: 类型){
 //第一行需要调用主构造器或者其他构造器
 //构造器代码  
}
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)
  }
}

单例对象

object 单例对象名{ } //定义一个单例对象
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方法

def main(args:Array[String]):Unit = {
//方法体
}

继承App特质

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

object 单例对象名 extends App{
  //方法体
}

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

//主入口
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称为伴生类

注意:

伴生对象必须要和伴生类一样的名字
伴生对象和伴生类在同一个scala源文件中
伴生对象和伴生类可以相互访问private属性
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],表示只能在当前类中访问。伴生对象也不可以访问

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方法

object 伴生对象名{
   def apply(参数名:参数类型, 参数名: 参数类型...) =  new (...)
}

创建对象

val 对象名 = 伴生对象名(参数1,参数2....)
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)
  }
}

继承

class/object A类 extends B类 {
  ...
}

继承

Monkey分为程序猿和金丝猴

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中,单例对象也可以继承类的

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字段。

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()
  }
}

类型判断

有两种方式

1.isInstanceOf:判断对象是否为指定类的对象
 asInstanceOf:将对象转换为指定类型
 
2.getClass/classOf:如果要求精确地判断出对象的类型就是指定的数据类型,那么就只能使用 getClass classOf 来实现.

isInstanceOf/asInstanceOf

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

getClass可以精确获取对象的类型
classOf[类名]可以精确获取数据类型
使用==操作符可以直接比较类型
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
}  
}

抽象类

//定义抽象类
abstract class 抽象类名{
   //定义抽象字段
   val/var 抽象字段名:类型
   //定义抽象方法
   def 方法名(参数:参数类型,参数: 参数类型...):返回类型
}
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)
  }
}

匿名内部类

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

new 类名(){
  //重新类中所有的抽象内容
}

使用场景

1.(成员方法)仅调用一次的时候.
2.可以作为方法的参数进行传递.
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)  
  }
}

特质

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

继承特质

class  extends 特质1 with 特质2{
   //重写抽象字段
   //重写抽象方法
}

注意:

1.scala中不管是类还是特质,继承关系用的都是extends关键字
2.如果要继承多个特质(trait),则特质名之间使用with关键字隔开
//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

//案例: 类继承多个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()
}
}