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