7. Scala面向对象编程(中级部分)
7.1 包
7.1.1 看一个应用场景
现在有两个程序员共同开发一个项目,程序员xiaoming希望定义一个类取名Dog,程序员xiaohong也想定一个类也叫Dog,两个程序员还为此吵了起来,该怎么办?
--->使用包即可解决这个问题
7.1.2 回顾-Java包的三大作用
1) 区分相同名字的类
2) 当类很多时,可以很好的管理类
3) 控制访问范围
7.1.3 回顾-Java打包命令
-打包基本语法
package com.c;
-打包的本质分析
实际上就是创建不同的文件夹来保存类文件
7.1.4 快速入门
使用打包技术来解决上面的问题,不同包下Dog类
public class TestTiger {
public static void main(String[] args) {
//使用xm的Tiger
com.c.scala_exercise.javapackage.xm.Tiger tiger01 = new com.c.scala_exercise.javapackage.xm.Tiger();
//使用xh的Tiger
com.c.scala_exercise.javapackage.xh.Tiger tiger02 = new com.c.scala_exercise.javapackage.xh.Tiger(); System.out.println("tiger01=" + tiger01 + "tiger02=" + tiger02);
}
}
7.1.5 Scala包的基本介绍
和Java一样,Scala中管理项目可以使用包,但Scala中的包的功能更加强大,使用也相对复杂些
7.1.6 Scala包快速入门
使用打包技术来解决上面的问题,不同包下Dog类
object boke_demo01 {
def main(args: Array[String]): Unit = {
//使用xh的Tiger
val tiger1 = new com.c.scala_exercise.scalapackage.xh.Tiger
//使用xm的Tiger
val tiger2 = new com.c.scala_exercise.scalapackage.xm.Tiger println(tiger1 + " " + tiger2) }
}
7.1.7 Scala包的特点概述
-基本语法
package 包名
-Scala包的作用(和Java一样)
1) 区分相同名字的类
2) 当类很多时,可以很好的管理类
3) 控制访问范围
4) 可以对类的功能进行扩展
-Scala中包名和源码所在的系统文件目录结构可以不一致,但是编译后的字节码文件路径和包名会保持一致(这个工作由编译器完成)
object boke_demo01 {
def main(args: Array[String]): Unit = {
//使用xh的Tiger
val tiger1 = new com.c.scala_exercise.scalapackage.xh.Tiger
//使用xm的Tiger
val tiger2 = new com.c.scala_exercise.scalapackage.xm.Tiger println(tiger1 + " " + tiger2) }
} class Employee { }
7.1.8 包的命名
-命名规则:
只能包含数字、字母、下划线、小圆点.,但是不能用梳子开头,也不要使用关键字
demo.class.exercise //错误,因为class是关键字
demo.12a //错误,因为不能以梳子开头
-命名规范:
一般是小写字母+小圆点一般是
com.公司名.项目名.业务模块名 比如:com.baidu.io.model com.baidu.io.controller
7.1.9 Scala包注意事项和使用细节
1) Scala进行package打包时,可以有如下形式
//代码说明
//1. package com.boke{} 表示我们创建了包 com.boke ,在{}中
// 我们可以继续写它的子包 scala //com.boke.scala, 还可以写类,特质trait,还可以写object
//2. 即Sacla支持,在一个文件中,可以同时创建多个包,以及给各个包创建类,trait和object
package com.boke { //包 com.boke // class User { // 在com.boke包下创建个 User类
// def sayHello(): Unit = {
// //想使用 com.boke.scala2包下的 Monster
// import com.boke.scala2.Monster
// val monster = new Monster()
// }
// }
//
// package scala2 { // 创建包 com.boke.scala2
// class User { // 在com.boke.scala2 包下创建个 User类
// }
//
// class Monster { //
//
// }
//
// } //
//说明
//1. 在包中直接写方法,或者定义变量,就错误==>使用包对象的技术来解决
//2. package object scala表示创建一个包对象scala, 它是com.boke.scala这个包对应的包对象
//3. 每一个包都可以有一个包对象
//4. 包对象的名字需要和子包一样
//5. 在包对象中可以定义变量,方法
//6. 在包对象中定义的变量和方法,就可以在对应的包中使用
//7. 在底层这个包对象会生成两个类 package.class 和 package$.class
package object scala {
var name = "king" def sayHiv(): Unit = {
println("package object scala sayHI~")
}
} package scala { //包 com.boke.scala class Person { // 表示在 com.boke.scala下创建类 Person
val name = "Nick" def play(message: String): Unit = {
println(this.name + " " + message)
}
} class User {
def testUser(): Unit = {
println("name = " + name)
sayHiv()
}
} object Test1 { //表示在 com.boke.scala 创建object Test1
def main(args: Array[String]): Unit = { println("name=" + name)
name = "yy"
sayHiv() // println("ok")
// //我们可以直接使用父包的内容
// //1.如果有同名的类,则采用就近原则来使用内容(比如包)
// //2.如果就是要使用父包的类,则指定路径即可
// val user = new User
// println("user=" + user) //
// val user2 = new com.boke.User()
// println("user2" + user2) }
} } }
2) 包也可以像嵌套类那样嵌套使用(包中有包),好处:可以在同一个文件中,将类(class/object)、trait创建在不同的包中,这样就非常灵活了
3) 作用域原则:可以直接向上访问。即Scala中子包中直接访问父包的内容,大括号体现作用域。(提示:Java中子包使用父包的类,需要import)。在子包和父包类重名时,默认采用就近原则,如果希望指定使用某个类,则带上包名即可
4) 父包要访问子包的内容时,需要import对应的类等
5) 可以在同一个.scala文件中声明多个并列的package(建议嵌套的package不要超过3层)
6) 包名可以相对也可以绝对,比如访问 BeanProperty 的绝对路径是: _root_.scala.beans.BeanProperty,在一般情况下,我们使用相对路径来引入包,只有当包名冲突时,使用绝对路径来处理
import scala.beans.BeanProperty class Manager(var name: String) {
//第一种形式 [使用相对路径引入包]
@BeanProperty var age: Int = _
//第二种形式, 和第一种一样,都是相对路径引入
@scala.beans.BeanProperty var age2: Int = _
//第三种形式, 是绝对路径引入,可以解决包名冲突
@_root_.scala.beans.BeanProperty var age3: Int = _
} object TestBean {
def main(args: Array[String]): Unit = {
val m = new Manager("jack")
println("m=" + m)
}
}
7.1.10 包对象
基本介绍:包可以包含类、对象和特质(trait),但不能包含函数/方法或变量的定义。这是Java虚拟机的局限。为了弥补这一点,Scala提供了包对象的概念来解决这个问题
7.1.11 包对象的应用案例
/说明
//1. 在包中直接写方法,或者定义变量,就错误==>使用包对象的技术来解决
//2. package object scala表示创建一个包对象scala, 它是com.boke.scala这个包对应的包对象
//3. 每一个包都可以有一个包对象
//4. 包对象的名字需要和子包一样
//5. 在包对象中可以定义变量,方法
//6. 在包对象中定义的变量和方法,就可以在对应的包中使用
//7. 在底层这个包对象会生成两个类 package.class 和 package$.class
package object scala {
var name = "king" def sayHiv(): Unit = {
println("package object scala sayHI~")
}
} package scala { //包 com.boke.scala class Person { // 表示在 com.boke.scala下创建类 Person
val name = "Nick" def play(message: String): Unit = {
println(this.name + " " + message)
}
} class User {
def testUser(): Unit = {
println("name = " + name)
sayHiv()
}
} object Test1 { //表示在 com.boke.scala 创建object Test1
def main(args: Array[String]): Unit = { println("name=" + name)
name = "yy"
sayHiv() }
} }
7.1.12 包对象的底层的实现机制
如图所示:一个包对象会生成两个类package和package$
如图所示:说明了包去使用包对象的变量或者方法的原理
7.1.13 包对象的注意事项
1) 每个包都可以有一个包对象,需要在父包中定义它
2) 包对象名称需要和包名一致,一般用来对包的功能补充
7.2 包的可见性问题
7.2.1 回顾-Java访问修饰符基本介绍
Java提供四种访问控制修饰符号来控制方法和变量的访问权限(范围)
1) 公开级别:用public修饰,对外公开
2) 受保护级别:用protected修饰,对于子类和同一包中的类公开
3) 默认级别:没有修饰符,向同一个包中的类公开
4) 私有级别:用private修饰,只有类本身可以访问,不对外公开
7.2.2 回顾-Java中4中访问修饰符的访问范围
7.2.3 回顾-Java访问修饰符使用注意事项
1) 修饰符可以用来修饰类中的属性,成员方法以及类
2) 只有默认的和public才能修饰类!并且遵循上述访问权限的特点
7.2.4 Scala中包的可见性介绍
在Java中,访问权限分为:public,private,protected和默认。在Scala中,可以通过类似的修饰符达到同样的效果,但是使用上有所区别
案例演示
object boke_demo01 { def main(args: Array[String]): Unit = {
val c = new Clerk()
c.showInfo()
Clerk.test(c) }
} //类
class Clerk {
var name: String = "jack" //
private var sal: Double = 9999.9
protected var age = 23
var job: String = "大数据工程师" def showInfo(): Unit = {
//在本类可以使用私有的
println(" name " + name + " sal= " + sal)
}
} object Clerk {
def test(c: Clerk): Unit = {
//这里体现出在伴生对象中,可以访问c.sal
println("test() name=" + c.name + " sal= " + c.sal)
}
}
7.2.5 Scala中包的可见性和访问修饰符的使用
1) 当属性访问权限为默认时,从底层看属性是private的,但是因为提供了xxx_$eq()[类似setter]/xxx()[类似getter]方法,因此从使用效果看是任何地方都可以访问
2) 当方法访问权限为默认时,默认为public访问权限
3) private为私有权限,只有在类的内部和伴生对象中可用
4) protected为受保护权限,Scala中受保护权限比Java中更为严格,只能子类访问,同包无法访问
5) 在Scala中没有public关键字,即不能用public显示的修饰属性和方法
6) 包访问权限(表示属性有了限制,同时包也有了限制),这点和Java不一样,体现出Scala包的灵活性
package com.scala.exercise class Person { //增加包访问权限后
//1.private同时起作用,不仅同类可以使用
//2.com.scala.exercise中包下的其它类也可以使用
private[exercise] val name = "Jack"
//当然,也可以将可见度延展到上层包
private[scala] val age = 23
//说明:private可以变化,比如protected[scala],非常的灵活
}
7) 整体的案例演示
object boke_demo01 { def main(args: Array[String]): Unit = {
val c = new Clerk()
c.showInfo()
Clerk.test(c) }
} //类
class Clerk {
var name: String = "jack" //
private var sal: Double = 9999.9
protected var age = 23
var job: String = "大数据工程师" def showInfo(): Unit = {
//在本类可以使用私有的
println(" name " + name + " sal= " + sal)
}
} //当一个文件中出现了 class Clerk 和 object Clerk
//1. class Clerk 称为伴生类
//2. object Clerk 的伴生对象
//3. 因为Scala设计者将static拿掉, 他就是设计了 伴生类和伴生对象的概念
//4. 伴生类 写非静态的内容 伴生对象 就是静态内容
//5.
object Clerk {
def test(c: Clerk): Unit = {
//这里体现出在伴生对象中,可以访问c.sal
println("test() name=" + c.name + " sal= " + c.sal)
}
} class Person {
//这里我们增加一个包访问权限
//下面private[scala] : 1,仍然是private 2. 在scala包(包括子包)下也可以使用name ,相当于扩大访问范围 protected[scala] val name = "Jack"
}
7.3 包的引入
7.3.1 Scala引入包基本介绍
Scala引入包也是使用import,基本的原理跟机制和Java一样,但是Scala中的import功能更佳强大,也更灵活。因为Scala语言源自Java,所以java.lang包中的类会自动引入到当前环境中,而Scala中的scala包和predef包的类也会自动引入到当前环境中,即起其下的类可以直接使用。如果想要把其它包中的类引入到当前环境中,需要使用import
7.3.2 Scala引入包的细节和注意事项
1) 在Scala中,import语句可以出现在任何地方,并不仅限于文件顶部,import语句的作用一直延伸到包含该语句的块末尾。这种语法的好处是:在需要时引入包,缩小import包的作用范围,提高效率
class User {
import scala.beans.BeanProperty
@BeanProperty var name : String = ""
} class Dog {
@BeanProperty var name : String = "" //可以吗? No
}
2) Java中如果想要导入包中所有的类,可以通过通配符*,Scala中采用_(下划线)
3) 如果不想要某个包中全部的类,而是其中几个类,可以采用选取器(大括号)
def test(): Unit = {
//可以使用选择器,选择引入包的内容,这里,我们只引入 HashMap, HashSet
import scala.collection.mutable.{HashMap, HashSet}
var map = new HashMap()
var set = new HashSet()
}
4) 如果引入的多个包中含有相同的类,那么可以将不需要的类进行重命名进行区分,这个就是重命名
def test2(): Unit = {
//下面的含义是 将 java.util.HashMap 重命名为 JavaHashMap
import java.util.{HashMap => JavaHashMap}
import scala.collection.mutable._
var map = new HashMap() // 此时的 HashMap 指向的是 scala 中的 HashMap
var map1 = new JavaHashMap(); // 此时使用的 java 中 hashMap 的别名 }
5) 如果某个冲突的类根本就不会用到,那么这个类可以直接隐藏掉
import java.util.{ HashMap=>_, _} // 含义为 引入 java.util 包的所有类,但是忽略 HahsMap 类.
var map = new HashMap()
7.4 面向对象编程方法-抽象
-如何理解抽象
我们在前面去定义一个类的时候,实际上就是把一类事物的共有的属性和行为提取出来,形成一个物理模型(模版),这种研究问题的方法称为抽象
7.5 面向对象编程三大特征
7.5.1 基本介绍
面向对象有三大特征:封装、继承、多态
7.5.2 封装介绍
封装(encapsulation)就是把抽象出的数据和对数据的操作封装在一起,数据被保护在内部,程序的其它部分只有通过被授权的操作(成员变量),才能对数据进行操作
7.5.3 封装的理解和好处
1) 隐藏实现细节
2) 可以对数据进行验证,保证安全合理
3) 同时可以加入业务逻辑
7.5.4 如何体现封装
1) 对类中的属性进行封装
2) 通过成员方法,包实现封装
7.5.5 封装的实现步骤
1) 将属性进行私有化
2) 提供一个公共的set方法,用于对属性判断并赋值
def setXxx(参数名 : 类型) : Unit = {
//加入数据验证的业务逻辑
属性 = 参数名
}
3) 提供一个公共的get方法,用于获取属性的值
def getXxx() [: 返回类型] = {
return 属性
}
7.5.6 Scala封装的注意事项的小结
1) Scala中为了简化代码的开发,当声明属性var时,本身就自动提供了对应setter/getter方法,如果属性声明为private的,那么自动生成的setter/getter方法也是private的,如果属性省略访问权限修饰符,那么自动生成的setter/getter方法时public的
2) 因此我们如果只是对一个属性进行简单的set和get,只要声明一下该属性(属性使用默认访问修饰符),不用写专门的set和get,默认会创建,访问时,直接对象.变量。这样也是为了保持访问一致性
3) 从形式上看 dog.food 直接访问属性,其实底层仍然是访问的方法,看一下反编译的代码就会明白
4) 有了上面的特性,目前很多新的框架,在进行反射时,也支持对属性的直接反射
7.6 面向对象编程-继承
7.6.1 Java继承的简单回顾
class 子类名 extends 父类名 { 类体 }
7.6.2 继承基本介绍和示意图
继承可以解决代码复用,让我们的编程更佳靠近人类的思维,当多个类存在相同的属性(变量)和方法时,可以从这些类中抽象出父类(比如Student),在父类中定义这些相同的属性和方法,所有的子类不需要重复定义这些属性和方法,只需要通过extends语句来声明继承父类即可。和Java一样,Scala也支持类的单继承
7.6.3 Scala继承的基本语法
class 子类名 extends 父类名 { 类体 }
7.6.4 Scala继承快速入门
object boke_demo01 { def main(args: Array[String]): Unit = {
//使用
val student = new Student
student.name = "jack" //调用了student.name()
student.studying()
student.showInfo()
}
} class Person { //Person类
var name: String = _
var age: Int = _ def showInfo(): Unit = {
println("学生信息如下:")
println("名字:" + this.name)
}
} //Student类继承Person
class Student extends Person {
def studying(): Unit = {
//这里可以使用父类的属性
println(this.name + "学习 scala中....")
}
}
7.6.5 Scala继承给编程带来的便利
1) 代码的复用性提高了
2) 代码的扩展性和维护性提高了
7.6.6 Scala子类继承了什么,怎么继承了
子类继承了所有的属性,只是私有的属性不能直接访问,需要通过公共的方法去访问[debug代码验证可以看到]
//说明
//1. 在scala中,子类继承了父类的所有属性
//2. 但是private的属性和方法无法访问 object boke_demo01 { def main(args: Array[String]): Unit = {
val sub = new Sub()
sub.sayOk()
//sub.test200() //编译器不让过.
}
} //父类(基类)
class Base {
var n1: Int = 1 //public n1() , public n1_$eq()
protected var n2: Int = 2
private var n3: Int = 3 // private n3() , private n3_$eq() def test100(): Unit = { // 默认 public test100()
println("base 100")
} protected def test200(): Unit = { // public
println("base 200")
} private def test300(): Unit = { //private
println("base 300")
} //编译原理->业务逻辑->性能优化
} //Sub 继承 Base
class Sub extends Base { def sayOk(): Unit = {
this.n1 = 20 //这里访问本质this.n1_$eq()
this.n2 = 40 println("范围" + this.n1 + this.n2) test100() //
test200() //在子类中使用protected
}
}
7.6.7 Scala重写方法
说明:Scala明确规定,重写一个非抽象方法需要用override修饰符,调用超类的方法使用super关键字
object boke_demo01 { def main(args: Array[String]): Unit = {
val emp = new Emp
emp.printName()
}
} //Person类
class Person {
var name: String = "tom" def printName() { //输出名字
println("Person printName() " + name)
} def sayHi(): Unit = {
println("sayHi...")
}
} //这里我们继承Person
class Emp extends Person {
//这里需要显式的使用override
override def printName() {
println("Emp printName() " + name)
//在子类中需要去调用父类的方法,使用super
super.printName()
sayHi()
}
}
7.6.8 Scala中类型检查和转换
-基本介绍
要测试某个对象是否属于某个给定的类,可以用isInstanceOf方法。用asInstanceOf方法将引用转换为子类的引用。classOf获取对象名
classOf[String]就如同Java的String.class
obj.isInstanceOf[T]就如同Java的 obj instanceofT 判断obj是不是T类型
obj.asInstanceOf[T] 就如同Java的(T)obj 将obj强转成T类型
-案例演示
object boke_demo01 { def main(args: Array[String]): Unit = { //ClassOf的使用,可以得到类名
println(classOf[String]) // 输出
val s = "king"
println(s.getClass.getName) //使用反射机制 //isInstanceOf asInstanceOf
var p1 = new Person
var emp = new Emp
//将子类引用给父类(向上转型,自动)
p1 = emp
//将父类的引用重新转成子类引用(多态),即向下转型
var emp2 = p1.asInstanceOf[Emp]
emp2.sayHello() }
} //Person类
class Person {
var name: String = "tom" def printName() { //输出名字
println("Person printName() " + name)
} def sayHi(): Unit = {
println("sayHi...")
}
} //这里我们继承Person
class Emp extends Person {
//这里需要显式的使用override
override def printName() {
println("Emp printName() " + name)
//在子类中需要去调用父类的方法,使用super
super.printName()
sayHi()
} def sayHello(): Unit = { }
}
-最佳实践
类型检查和转换的最大价值在于:可以判断传入对象的类型,然后转成对应的子类对象,进行相关操作,这里也体现出多态的特点
7.6.9 Java中超类的构造
说明:从代码可以看出,在Java中,创建子类对象时,子类的构造器总是去调用一个父类的构造器(显示或者隐式调用)
public class JavaBaseConstractor { public static void main(String[] args) { //1.A()
//2.B()
B b = new B(); //1.A(String name) jack
//2.B(String name) jack
B b2 = new B("jack"); }
} class A {
public A() {
System.out.println("A()");
} public A(String name) {
System.out.println("A(String name)" + name);
}
} class B extends A {
public B() {
//这里会隐式调用super(); 就是无参的父类构造器A()
//super();
System.out.println("B()");
} public B(String name) {
super(name);
System.out.println("B(String name)" + name);
}
}
7.6.10 Scala中超类的构造
1) 类有一个主构造器和任意数量的辅助构造器,而每个辅助构造器都必须先调用主构造器(也可以是间接调用)
2) 只有主构造器可以调用父类的构造器,辅助构造器不能直接调用父类的构造器,在Scala的构造器中,不能调用super(params)
3) 案例演示
object boke_demo01 { def main(args: Array[String]): Unit = { //分析执行的顺序
//1.Person...
//2.Emp ....
//3.Emp 辅助构造器~
val emp1 = new Emp("smith") println("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%")
//Person..
//Emp ....
val emp2 = new Emp("terry", 10)
emp2.showInfo() // 雇员的名字 terry }
} //父类Person
class Person(pName: String) {
var name = pName
println("Person...") def this() {
this("默认的名字")
println("默认的名字") }
} //子类Emp继承Person
class Emp(eName: String, eAge: Int) extends Person(eName) { println("Emp ....") //辅助构造器
def this(name: String) { this(name, 100) // 必须调用主构造器
this.name = name
println("Emp 辅助构造器~")
} def showInfo(): Unit = {
println("雇员的名字 ", name)
}
}
7.6.11 覆写字段
-基本介绍
在Scala中,子类改写父类的字段,我们称之为覆写/重写字段。覆写字段需要使用override修饰
-回顾
在Java中只有方法的重写,没有属性/字段的重写,准确的讲,是隐藏字段代替了重写
-回顾-Java另一重要特性:动态绑定机制
动态绑定机制:
1) 如果调用的是方法,则JVM机会将改方法和对象的内存地址绑定
2) 如果调用的是一个属性,则没有动态绑定机制,在哪里调用就返回对应值
public class JavaDaynamicBind {
public static void main(String[] args) { //将一个子类的对象地址,交给了一个AA(父类的)引用
//java的动态绑定机制的小结
//1.如果调用的是方法,则Jvm机会将该方法和对象的内存地址绑定
//2.如果调用的是一个属性,则没有动态绑定机制,在哪里调用,就返回对应值
AA obj = new BB();
System.out.println(obj.sum()); // 30
System.out.println(obj.sum1()); // 20 }
} class AA {
public int i = 10; public int sum() {
return getI() + 10;
} public int sum1() {
return i + 10;
} public int getI() {
return i;
}
} class BB extends AA {
public int i = 20; public int getI() {
return i;
} }
-Scala覆写字段快速入门
object ScalaFiledOverride { def main(args: Array[String]): Unit = {
val obj1: AAA = new AAA
val obj2: BBB = new BBB
//obj1.age => obj1.age() //动态绑定机制
//obj2.age => obj2.age()
println("obj1.age=" + obj1.age + "\t obj2.age=" + obj2.age)
}
} class AAA {
val age: Int = 10 // 会生成 public age()
} class BBB extends AAA {
override val age: Int = 20 // 会生成 public age()
}
反编译后的代码:
-覆写字段的注意事项和细节
1) def只能重写另一个def(即:方法只能重写另一个方法)
2) val只能重写另一个val属性 或 重写不带参数的def
-案例演示1(val只能重写另一个val属性)
object ScalaFiledOverride { def main(args: Array[String]): Unit = {
val obj1: AAA = new AAA
val obj2: BBB = new BBB
//obj1.age => obj1.age() //动态绑定机制
//obj2.age => obj2.age()
println("obj1.age=" + obj1.age + "\t obj2.age=" + obj2.age)
}
} //如果 val age 改成 var 报错
class AAA {
val age: Int = 10 // 会生成 public age()
} class BBB extends AAA {
override val age: Int = 20 // 会生成 public age()
}
-案例演示2(重写不带参数的def)
object boke_demo01 { def main(args: Array[String]): Unit = {
val b1 = new BB()
println(b1.sal) // 0
val b2: AA = new BB()
println("b2.sal=" + b2.sal()) // 0
}
} class AA {
def sal(): Int = {
return 10
}
} class BB extends AA {
override val sal: Int = 0 //底层 public sal
}
3) var只能重写另一个抽象的var属性
object boke_demo01 { def main(args: Array[String]): Unit = {
println("hello~")
}
} //在AA中,有一个抽象的字段(属性)
//1. 抽象的字段(属性):就是没有初始化的字段(属性)
//2. 当一个类含有抽象属性时,则该类需要标记为abstract
//3. 对于抽象的属性,在底层不会生成对应的属性声明,而是生成两个对应的抽象方法(name name_$eq)
abstract class AA {
var name: String //抽象
var age: Int = 10
} class Sub_AA extends AA {
//说明
//1. 如果我们在子类中去重写父类的抽象属性,本质是实现了抽象方法
//2. 因此这里我们可以写override ,也可以不写
override var name: String = "" }
-抽象属性:声明未初始化的变量就是抽象的属性,抽象属性在抽象类中
-var重写抽象的var属性小结
1) 一个属性没有初始化,那么这个属性就是抽象属性
2) 抽象属性在编译成字节码文件时,属性并不会声明,但是会自动生成抽象方法,所以类必须声明为抽象类
3) 如果是覆写一个父类的抽象,那么override关键字可以省略[原因:父类的抽象属性,生成的是抽象方法,因此不涉及到方法重写的概念,override可以省略]
7.6.12 抽象类
-基本介绍
在Scala中,通过abstract关键字标记不能被实力化的类。方法不用标记abstract,只要省掉方法体即可,抽象类可以拥有抽象字段,抽象字段/属性就是没有初始值的字段
-快速入门案例
将Animal做成抽象类,包含一个抽象方法cry()
object AbstractDemo01 {
def main(args: Array[String]): Unit = {
}
} //抽象类
abstract class Animal {
var name: String //抽象的字段
var age: Int // 抽象的字段
var color: String = "black" //普通属性
def cry() //抽象方法,不需要标记 abstract
}
7.6.13 Scala抽象类使用的注意事项和细节
1) 抽象类不能被实例
//默认情况下,一个抽象类是不能实例化的,但是你实例化时,动态的实现了抽象类的所有 //抽象方法,也可以,如下
val animal = new Animal {
override def sayHello (): Unit = {
println ("say hello~~~~")
}
}
animal.sayHello ()
2) 抽象类不一定要包含abstract方法,也就是说,抽象类可以没有abstract方法
abstract class Animal {
//在抽象类中可以有实现的方法
def sayHi (): Unit = {
println("hello") }
}
3) 一旦类包含了抽象方法或者抽象属性,则这个类必须声明为abstract
4) 抽象方法不能有主体,不允许使用abstract修饰
5) 如果一个类继承了抽象类,则它必须实现抽象类中所有的抽象方法和抽象属性,除非它自己也声明为abstract类
abstract class Animal { def sayHello()
var food: String
} class Dog extends Animal { override def sayHello(): Unit = {
println("小狗汪汪叫!")
} override var food: String = _
}
6) 抽象方法和抽象属性不能使用private、final来修饰,因为这些关键字都是和重写/实现相违背的
7) 抽象类中可以有实现的方法
8) 子类重写抽象方法不需要override,写上也不会错
7.6.14 匿名子类
-基本介绍
和Java一样,可以通过包含带有定义或重写的代码块的方式创建一个匿名的子类
-回顾-Java中匿名子类的使用
public class NoNameDemo01 {
public static void main(String[] args) {
//在java中去创建一个匿名子类对象
A a = new A() {
@Override
public void cry() {
System.out.println("cry...");
}
};
a.cry();
}
} abstract class A {
abstract public void cry();
}
-Scala匿名子类的使用
object boke_demo01 { def main(args: Array[String]): Unit = {
val monster = new Monster {
override def cry(): Unit = {
println("...:)")
} override var name: String = _
}
monster.cry()
}
} abstract class Monster {
var name: String def cry()
}
7.6.15 继承层级
-Scala继承层级一览图
-对上图的一个小结
1) 在Scala中,所有其它类都是AnyRef的子类,类似Java的Obiect
2) AnyVal和AnyRef都扩展自Any类,Any类是子节点
3) Any中定义了isInstanceOf、asInstanceOf方法,以及哈希方法等
4) Null类型的唯一实例就是null对象,可以将null赋值给任何引用,但不能赋值给值类型的变量
5) Nothing类型没有实例,它对于泛型结构是有用处的,举例:空列表Nil的类型就是List[Nothing],它是List[T]的子类型,T可以是任何类
7. Scala面向对象编程(中级部分)的更多相关文章
- 大数据技术之_16_Scala学习_05_面向对象编程-中级
第七章 面向对象编程-中级7.1 包7.1.1 Java 中的包7.1.2 Scala 中的包7.1.3 Scala 包的特点概述7.1.4 Scala 包的命名7.1.5 Scala 会自动引入的常 ...
- Python 第六篇(中):面向对象编程中级篇
面向对象编程中级篇: 编程思想概述: 面向过程:根据业务逻辑从上到下写垒代码 #最low,淘汰 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可 #混口饭吃 def add(ho ...
- 6. Scala面向对象编程(基础部分)
6.1 基本介绍 6.1.1 Scala语言是面向对象的 1) Java时面向对象的编程语言,由于历史原因,Java中海存在着非面向对象的内容:基本类型,null,静态方法等 2) Scala语言来自 ...
- Scala面向对象编程与类型系统
Scala支持面向对象编程, 其面向对象特性与Java有共同之处并添加了很多新的特性. 类定义 scala使用class关键字定义类: class MyComplex(real0:Double, im ...
- 大数据笔记(二十四)——Scala面向对象编程实例
===================== Scala语言的面向对象编程 ======================== 一.面向对象的基本概念:把数据和操作数据的方法放到一起,作为一个整体(类 c ...
- Scala实战高手****第7课:零基础实战Scala面向对象编程及Spark源码解析
/** * 如果有这些语法的支持,我们说这门语言是支持面向对象的语言 * 其实真正面向对象的精髓是不是封装.继承.多态呢? * --->肯定不是,封装.继承.多态,只不过是支撑面向对象的 * 一 ...
- 2.3 Scala面向对象编程基础
一.类 1.类的定义 Unit表示什么都不返回 方法体最后一句的值,就是方法的返回值. 2.类成员的可见性 3.方法的定义方式 定义方法的时候加圆括号,调用时可以加圆括号c.getValue()也可以 ...
- 8. Scala面向对象编程(高级部分)
8.1 静态属性和静态方法 8.1.1 静态属性-提出问题 有一群小孩在玩堆雪人,不时有新的小孩加入,请问如何知道现在共有多少人在玩?请使用面向对象的思想,编写程序解决 8.1.2 基本介绍 -Sca ...
- 7、scala面向对象编程之类
1. 定义一个简单的类 2.getter与setter 3.自定义getter与setter方法 4.仅暴露field的getter方法 5.private[this]的使用 6.Java风格的ge ...
随机推荐
- 选美?作秀?MES系统的选择更应该从实际出发
MES选型不是做秀,不是选美. 如今不少企业在信息化推广应用过程中面面求好.追求完美,用意没错,然而在MES开发过程中,软件商不可能将今后各种可能出现的问题考虑周全,不可能将系统做到十全十美.随着系统 ...
- 高性能TcpServer(Python) - SocketServer
源码下载 -> 提取码 QQ:505645074 程序结构图 测试截图 1. 正常接收测试 2. 并发测试
- CRM product model的用法
User scenario An example from sap help For a car, the interior, the engine capacity, and the exterio ...
- 一些你所不知道的VS Code插件
摘要: 你所不知道的系列. 原文:提高 JavaScript 开发效率的高级 VSCode 扩展之二! 作者:前端小智 Fundebug经授权转载,版权归原作者所有. 作为一名业余爱好者.专业人员,甚 ...
- VirtualBox打开VMware虚拟机
下载安装VirtualBox 打开VirtualBox,选择新建 设置如下: 之后就可以直接打开虚拟机了.
- Python从零开始——基本数据类型
- MySQL的select多表查询
select 语句: select 语句一般用法为: select 字段名 from tb_name where 条件 ; select 查询语句类型一般分为三种: 单表查询,多表查询,子查询 最简 ...
- 关于METRIC SPACE中的一些概念对比(sequence and net)
由于LaTeX 和其他的编辑软件都不太好用,所以采用手写笔记的方式. ——一个想学代几的大二小萌新
- 工作不久的安卓开发者,他们是这样规划自己的Android学习路线
Android开发工作者工作不久的时候,会有一段迷茫期,觉得自己应该再学一点,却不知道从何学起,该怎样规划自己的学习路线呢?今天,我给大家梳理一下Android基础,就像建造房屋一样,要建造一座宏伟的 ...
- mysql基础知识之数据类型与约束
一.约束 作用: 保证数据的完整性和一致性表的设计 1.not null 和 default not null 是放在最后用来约束 前面 数据类型的 (在原有基础上本来可以主键后面可以为空,但是一旦在 ...