版权声明:本文为博主原创文章,未经博主允许不得转载!!
欢迎访问:https://blog.csdn.net/qq_21439395/article/details/81057459
交流QQ: 824203453
Scala的类与Java、C++的类比起来更简洁,学完之后你会更爱Scala!!!
对象: 使用object关键字修饰的
类: 使用class关键字修饰的
new 类: 类的实例(对象)
Scala中没有静态方法和静态字段,没有static,
java中,没有关键字修饰的方法,只能用new class().方法
so 对于一个class来说,所有的方法和成员变量在实例被 new 出来之前都无法访问
虽然可以在class中定义main方法,然并卵…
但是可以使用object这个语法结构来达到同样的目的
用object关键字修饰的对象是单例的,称为单例对象,静态对象。
//单例对象
object ScalaSingleton {
def saySomething(msg: String) = {
println(msg)
}
}
object test {
def main(args: Array[String]): Unit = {
ScalaSingleton.saySomething("singleton....")
println(ScalaSingleton)
println(ScalaSingleton)
// 输出结果:
// cn.demo.ScalaSingleton$@28f67ac7
// cn.demo.ScalaSingleton$@28f67ac7
}
}
伴生对象是一种特殊的单例对象。是一种相对概念,需要满足两个条件:
条件1:在同一个源文件中,
条件2:对象名和类名相同
这样的单例对象,被称作是这个类的伴生对象。类被称为是这个单例对象的伴生类。
结论:类和伴生对象之间可以相互访问私有的方法和属性
class Dog {
val id = 1
private var name = "xiaoqing"
def printName(): Unit ={
//在Dog类中可以访问伴生对象Dog的私有属性
println(Dog.CONSTANT + name )
}
}
/**
* 伴生对象
*/
object Dog {
//伴生对象中的私有属性
private val CONSTANT = "汪汪汪 : "
def main(args: Array[String]) {
val p = new Dog
//访问私有的字段name
p.name = "123"
p.printName()
}
}
通常我们会在类的伴生对象中定义apply方法,当遇到对象名(参数1,...参数n)时apply方法会被调用
正常情况下,对象调用时是不能带参数的,但是如果能找到对应的apply方法,就能调用成功。
当使用对象(参数列表)来调用对象时,会去对象中找对应参数的apply方法,如果找到就执行相应的逻辑,如果找不到,就报错。
注意:只能找到和参数列表对应的apply方法。
要和对象区分开来
ApplyDemo // 对象
ApplyDemo() // ApplyDemo.apply() 方法
该语法的目的:不需通过new关键字,更方便的完成类和实例对象的初始化。
object ApplyDemo {
def apply(i:Int):Int = {
i * i
}
def main(args: Array[String]) {
//调用了Array伴生对象的apply方法
//def apply(x: Int, xs: Int*): Array[Int]
//arr1中只有一个元素5
val arr1 = Array[Int](5)
println(arr1.toBuffer)
println(ApplyDemo(1))
}
}
apply方法,是object上的方法。
1, 对象没有构造方法,不能加参数
objectTest2{
def main(args: Array[String]): Unit = {
Test2 // 这是一个对象,对象上不能有参数
Test2() // 添加参数之后,就报错了
}
}
2, 但是,如果对象(参数列表),实际上调用的是对象上的apply方法,具体会根据参数列表的个数,参数的类型去找对象上对应的apply方法,如果没找到,就报错。返回值类型取决于apply的返回类型
3, apply方法的作用,3.1,快速的创建类的实例对象
// apply 方法的主要作用是创建类的实例对象
def apply(): ApplyDemo = new ApplyDemo()
3.2,可以方便的对数组进行初始化。 val arr = Array(1, 3, 5, 6)
4,apply方法相当于java中的方法重载,可以定义对个apply方法,具体的参数类型,参数个数,以及返回值都是可以自定义的。
Scala程序都必须从一个对象的main方法开始,可以通过扩展App特质,不写main方法。
object AppObjectDemo extends App{
//不用写main方法
println("I love you Scala")
}
在Scala中,类并不用声明为public。
Scala源文件中可以包含多个类,所有这些类都具有公有可见性。
var 修饰的变量, 这个变量对外提供getter setter方法
val 修饰的变量,是只读属性 对外提供了getter方法,没有setter(相当于java中用final修饰的变量)
class Student {
val id= 666
// _ 表示一个占位符, 编译器会根据变量的具体类型赋予相应初始值
// 注意: 使用_ 占位符是, 变量类型必须指定
var name: String = _
//用var修饰的变量既有getter又有setter
var age: Int = 20
}
object Test{
val name: String = "zhangsan"
def main(args: Array[String]): Unit = {
// 调用空参构造器,
val student = new Student()
student.name = "laowang"
// 类中使用val修饰的变量不能更改
// student.age = 20
println(s"student.name ====== ${student.name} ${student.age}")
println("Test.name ======" + Test.name)
}
}
同java中的构造方法
构造器分为两类:主构造器,辅助构造器
主构造器直接在类名后面定义。
每个类都有主构造器,主构造器的参数直接放置类名后面,与类交织在一起。
如果没有定义构造器, 类会有一个默认的空参构造器
辅助构造器自定义,使用def this关键字,而且必须调用主构造器,或者其他的辅助构造器
注意:主构造器会执行类定义中的所有语句
/**
*每个类都有主构造器,主构造器的参数直接放置类名后面,与类交织在一起
*/
class Person(val name: String, val age: Int){
//主构造器会执行类定义中的所有语句
println("执行主构造器")
private var gender = "male"
//用this关键字定义辅助构造器
def this(name: String, age: Int, gender: String){
//每个辅助构造器必须以主构造器或其他的辅助构造器的调用开始
this(name, age)
println("执行辅助构造器")
this.gender = gender
}
var account1:String=_
def this(name:String,age:Int,gender:String){
this(name,age)
this.gender=gender
}
def this(name:String,age:Int,gender:String,account:String){
this(name,age,gender)
this.account1=account
}
println("尼玛,这里还是主构造器")
}
object Person {
def main(args: Array[String]): Unit = {
val s = new Person ("laoduan", 38)
println(s"${s.name} ${s.age}")
val s1 = new Person (“dingding", 18, "female")
println(s"${s1.gender}")
val p2 =new Person("xx2",12,"female","9527")
println(s"${p2.age},${p2.account1}")
}
}
scala的构造器总结:
1, 有两类构造器:主构造器,辅助构造器
2, 构造器的定义位置,
主构造器和类交织在一起,classStudent2(val name: String, var age: Int)
3, 辅助构造器是一个特殊的方法,定义在类中 def this(name:String,age:Int,gender:String)
4, 辅助构造器,第一行必须调用主构造器(或者其他的辅助构造器)
5, 辅助构造器的参数不能和主构造器的参数完全一致(参数个数,参数类型,参数顺序)
6, 可以定义空参的辅助构造器,但是主构造器的参数必须进行初始化赋值
7, 作用域:辅助构造器的作用域,只在方法中,主构造器的作用域是类中除了成员属性和成员方法之外的所有范围(可以通过反编译查看源码)
成员变量的访问权限
默认权限是public 任何地方都可以访问
private作用域 类和其伴生对象中
private [this],作用域为当前类中,伴生对象中无效
private [packageName] 指定包及其子包有效
/*
* private var age
* age 在这个类中是有getter setter方法的
* 但是前面如果加上了private 修饰, 也就意味着, age只能在这个类的内部以及其伴生类对象中可以访问修改
* 其他外部类不能访问
* */
class Student3 private (val name: String, private var age: Int) {
var gender: String = _
// 辅助构造器, 使用def this
// 在辅助构造器中必须先调用类的主构造器
def this(name: String, age:Int, gender: String){
this(name, age)
this.gender = gender
}
// private[this]关键字标识该属性只能在类的内部访问, 伴生类不能访问
private[this] val province: String = "北京市"
def getAge = 18
}
// 类的伴生对象
object Student3 {
def main(args: Array[String]): Unit = {
// 伴生对象可以访问类的私有方法和属性
val s3 = new Student3("Angelababy", 30)
s3.age = 29
println(s"${s3.age}")
// println(s"${s3.province}") 伴生类不能访问
}
}
方法的访问权限
通用于主构造器,辅构造器,以及普通方法
默认权限是共有的
private作用域为类和其伴生对象
private [this],作用域为当前类中,伴生对象中无效
private [packageName] 指定包及其子包有效 包名的写法,直接写报名,不需要层级路径
主构造器上一样适用于该方法的访问权限
private [cn.edu360.day03] 错误的
private [day03] 正确的
/*
* private 加在主构造器前面标识这个主构造器是私有的, 外部不能访问这个构造器
* */
class Student2 private (val name: String, var age: Int) {
var gender: String = _
// 辅助构造器, 使用def this
// 在辅助构造器中必须先调用类的主构造器
def this(name: String, age:Int, gender: String){
this(name, age)
this.gender = gender
}
}
object Student2 {
def main(args: Array[String]): Unit = {
val s1 = new Student2("laoYang", 18, "male")
println(s"${s1.gender}")
}
}
类包的访问权限
private 作用域为当前包及其子包 同 private[this]
private [packageName]作用域为指定包及其子包
/*
* private[包名] class 放在类最前面, 是修饰类的访问权限, 也就是说类在某些包下不可见或不能访问
* private[edu360] class 代表student4在edu360包下及其子包下可以见, 同级包中不能访问
* */
private[this] class Student4(val name: String, private var age: Int) {
var xx: Int = _
}
object Student4{
def main(args: Array[String]): Unit = {
val s = new Student4("张三", 20)
println(s"${s.name}")
}
}
访问权限总结:
对于成员属性 ,成员方法;(主构造器,辅助构造器,普通的方法)
public:默认的访问权限
private:在类及其伴生对象中有效,其他地方无效
private [this] :只在类的范围内有效,伴生对象中无效,其他地方无效
private [package] : 在指定包及其 子包范围内有效
package: 只能是一个具体的包名,不能是一个路径
private [scala29] 正确的
private [scala29.day04] 错误的
对于类:
public : 默认的权限 ,公有的
private ,private[this] 在当前包及其子包范围内有效
private [package] 在指定包及其子包范围内有效
在Scala中, 使用abstract修饰的类称为抽象类. 在抽象类中可以定义属性、未实现的方法(抽象方法)和具体实现的方法。
/*
* abstract修饰的类是一个抽象类
* */
abstract class Animal {
println("Animal's constructor ....")
// 定义一个name属性
val name: String = "animal"
// 没有任何实现的方法
def sleep()
// 带有具体的实现的方法
def eat(f: String): Unit = {
println(s"$f")
}}
类和对象,该怎么选择?
class object
一般情况下,使用object + 伴生的class
1, 优先使用object,object本质上拥有了的类的所有特性,object中没有构造器,也没有参数,必须要有程序入口,object,main方法,必不可少。
2, 如果是单例的,优先选择object,如果是多例的(封装数据,构造器),必须选择类
3, 伴生类和伴生对象都会用到。首先把object写上,如果需要有类的功能,就把伴生类写上。
scala中没有interface implements
Trait(特质)相当于 java的接口。比接口功能更强大。特质中可以定义属性和方法的实现。
Scala的类只能够继承单一父类,但是可以实现(继承,混入)多个特质(Trait)使用的关键字是 with和extends
特质不能有任何的类参数,即传递给类的主构造器的参数。
trait PointTest(x:Int, y: Int) // 编译不过
traitT1 {
// 定义普通方法,有方法实现
def youcanfly()={
println("tai feng lai le you can fly")
}
}
trait T2 {
// 定义一个属性
val className: String = "NB大神班"
// 定义一个没有实现的方法,默认就是抽象方法
def teacherSay(name: String)
// 定义带有具体的实现的方法
def doSomething() = {
println("群主开始发红包了...")
}
}
动态混入特质。
object test{
def main(args: Array[String]): Unit = {
// 动态混入特征,让类有了特质的方法
val t1 = new Teacher with T1
println(t1.youcanfly())
// 动态混入特质不能使用extends关键字,可同时混入多个特质
val t = new Teacher() with T1 with T2{
// 如果特质中有抽象方法,则必须重写该抽象方法,可以不使用override关键字
def teacherSay(name:String)={
println(s"最高face,${name}")
}
// 重写一个有具体的实现的方法,必须使用关键字override
overridedef doSomething() = {
println("群主:抢到红包继续接龙...")
}
}
println(t.teach("laozhao"))
println(t.doSomething)
println(t.youcanfly())
}
}
class Teacher{
}
比较:scala的trait和java中的interface的异同?
1,java的interface只定义方法名称和参数列表,不能定义方法体。而trait则可以定义方法体。
2,在java中实现接口用implements,而在scala中,实现trait用extends和with。
3,java的interface和scala的trait的最大区别是,scala可以在一个class实例化的时候动态混入trait。
用特质还是用抽象类??
1,优先使用特质。一个类可以扩展多个特质,但却只能扩展一个抽象类。
2,如果需要构造器,使用抽象类。因为抽象类可以定义带参数的构造器,而特质不行。
在Scala中扩展类的方式和Java一样都是使用extends关键字
在Scala中重写一个非抽象的方法必须使用override修饰符
// 定义一个抽象类
abstract class Animal(val age: Int) {
println("Animal`s main constructor invoked" + age)
//定义一个抽象方法
def run()
def breath(): Unit = {
println("呼吸氧气")
}
}
// 定义一个特质,定义一个普通方法
trait Fightable {
def fight(): Unit = {
println("用嘴咬")
}
}
// 定义一个特质,一个抽象方法
trait Flyable {
// 定义一个抽象方法
def fly()
}
定义一个bird类,实现多个特质
//在scala中,不论是继承还是实现特质,第一个都用extends关键字
class Bird extends Flyable with Fightable {
override def fly(): Unit = {
println("用翅膀飞")
}
}
object Bird {
def main(args: Array[String]): Unit = {
val b = new Bird
b.fly()
}
}
定义一个类,继承类,并实现多个trait
class Monkey(age: Int) extends Animal(age) with Flyable with Fightable {
//重写抽象的方法, 可以不加override关键字
def run(): Unit = {
// super()
println("跳着跑")
}
//重写非抽象的方法,必须加override关键字
override def breath(): Unit = {
println("猴子呼吸")
}
override def fly(): Unit = {
println("乘着筋斗云飞")
}
override def fight(): Unit = {
println("用棒子打")
}
println("monkey`s main constructor invoked" + age)
}
object Monkey {
def main(args: Array[String]): Unit = {
val a: Animal = new Monkey(100)
a.breath()
}
}
特质和抽象类的总结:
1, 单继承,多实现
2, 继承父类,使用extends,实现(混入)特质 使用 with和extends
3, 当类没有父类,那么实现的第一个特质,使用extends关键字,其他地方都使用with
4, 不论是继承父类,还是实现特质,都必须实现抽象方法,实现抽象方法可以不用override关键字,但是如果要重写一个普通方法,必须加上override关键字
5, scala的面向对象,具备了面向对象的封装继承和多态 三大特性。
6, 特质可以在类实例化的时候动态混入,使用的关键字是with,如果有抽象方法必须实现。动态混入了特质的对象,
// 在类实例化的时候,混入特质
val t: Teachers with TraitDemo with TraitDemo2 = new Teachers() with TraitDemo with TraitDemo2 {
override def say(): Unit = {
println("明天放假,so happy")
}
}
* 三大特性 封装 继承 多态
* 多态的满足条件?
* 1,继承父类 或者实现接口
* 2,重写父类或者接口的方法
* 3,父类引用指向子类对象,或者接口引用指向实现类
* scala 的面向 对象
val a:Animal = new Dog()
a.eat()
a.weap("xxoo")
样例类:使用case关键字 修饰的类,重要的特征就是支持模式匹配,多例
样例object:使用case关键字修饰的对象,支持模式匹配,单例
caseclass 和class的一些区别:
case class在初始化的时候,不用new,而普通类初始化时必须要new。
case class重写了toString方法。
默认实现了equals和hashCode
case class 实现了序列化接口 with Serializable
case class支持模式匹配(最重要的特征),所有case class 必须要有参数列表
有参数用case class,无参用case object
caseclass,和case object,可以当作消息进行传递
/*
* 样例类,使用case 关键字 修饰的类, 其重要的特征就是支持模式匹配
* */
case class Message(msg: String)
/**
* 样例object, 不能封装数据, 其重要特征就是支持模式匹配
*/
case object CheckHeartBeat
object TestCaseClass extends App{
// 可以不使用new 关键字创建实例
val msg = Message("hello")
println(msg.msg)
}
版权声明:本文为博主原创文章,未经博主允许不得转载!!
欢迎访问:https://blog.csdn.net/qq_21439395/article/details/81057459
交流QQ: 824203453