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方法必须放在一个单例对象中。
def main(args:Array[String]):Unit = { //方法体 }
创建一个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],表示只能在当前类中访问。伴生对象也不可以访问
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) } }
在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 来实现.
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[类名]可以精确获取数据类型 使用==操作符可以直接比较类型
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() } }
本文分享自微信公众号 - 后端技术学习(gh_9f5627e6cc61),作者:路行的亚洲
原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。
原始发表时间:2020-10-01
本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。
我来说两句