一、包
回顾-Java如何引入包
语法: import 包;
比如 import java.awt.*;
我们引入一个包的主要目的是要使用该包下的类
比如 import java.util.Scanner; 就只是引入一个类Scanner。
回顾-Java包的特点
java中包名和源码所在的系统文件目录结构要一致,并且编译后的字节码文件路径也和包名保持一致。
Scala包的基本介绍
和Java一样,Scala中管理项目可以使用包,但Scala中的包的功能更加强大,使用也相对复杂些。
1、Scala包的特点概述
基本语法
package 包名
Scala包的三大作用(和Java一样)
1. 区分相同名字的类
2. 当类很多时,可以很好的管理类
3. 控制访问范围
Scala中包名和源码所在的系统文件目录结构要可以不一致,但是编译后的字节码文件路径和包名
会保持一致(这个工作由编译器完成)。
2、Scala包的命名
命名规则:
只能包含数字、字母、下划线、小圆点.,但不能用数字开头, 也不要使用关键字。
例如:
demo.class.exec1 //错误 , 因为class是关键字
demo.12a // 错误,因为不能以数字开头
命名规范:
一般是小写字母+小圆点一般是:com.公司名.项目名.业务模块名
比如:com.tx.oa.model
com.ali.oa.controller
com.sina.edu.user
com.sohu.bank.order
3、Scala会自动引入的常用包
Scala包注意事项和使用细节
1. scala进行package 打包时,可以有如下形式。
/**
* 代码说明:
* 1. package com.lj.scala{} 表示创建了包com.lj.scala在{}中
* 2. 可以继续写它的子包packagetest,还可以继续写类,特质trait,还可以写object
* 3. 即Scala支持,在一个文件中,可以同时创建多个包,以及给各个包创建类,trait和object
*/
package com.lj.scala { // 包:com.lj.scala
/**
* @author Administrator
* @create 2020-03-10
*/
package packagetest { // 包:com.lj.scala.packagetest
class Person { // 表示在包:com.lj.scala.packagetest创建类Person
val name: String = "Leo"
def play(message: String): Unit = {
println(this.name + " " + message)
}
}
object test { // 表示在包:com.lj.scala.packagetest创建object Test
def main(args: Array[String]): Unit = {
println("OK!!!")
}
}
}
}
2. 包也可以像嵌套类那样嵌套使用(包中有包), 这个在前面的第三种打包方式已经讲过了,在使用
第三种方式时的好处是:程序员可以在同一个文件中,将类(class / object)、trait 创建在不同的包中,
这样就非常灵活了;
3. 作用域原则:可以直接向上访问。即: Scala中子包中直接访问父包中的内容, 大括号体现作用域;
4. 父包要访问子包的内容时,需要import对应的类等
package com.ali{
//引入在com.ali包中希望使用到子包的类Tiger,因此需要引入.
import com.ali.scala.Tiger
//这个类就是在com.ali包下
class User{
}
package scala {
//Tiger在com.ali.scala包中
class Tiger {
}
}
object Test2 {
def main(args: Array[String]): Unit = {
//如果要在父包使用到子包的类,需要import (import com.ali.scala.Tiger)
val tiger = new Tiger()
println("tiger=" + tiger)
}
}
}
5. 可以在同一个.scala文件中,声明多个并列的package(建议嵌套的pakage不要超过3层);
6. 包名可以相对也可以绝对:
比如,访问BeanProperty的绝对路径是:_root_.scala.beans.BeanProperty,
在一般情况下:我们使用相对路径来引入包,只有当包名冲突时,使用绝对路径来处理。
package com.ali.scala2
class Manager( var name : String ) {
//第一种形式
//@BeanProperty var age: Int = _
//第二种形式, 和第一种一样,都是相对路径引入
//@scala.beans.BeanProperty var age: Int = _
//第三种形式, 是绝对路径引入,可以解决包名冲突
@_root_. scala.beans.BeanProperty var age: Int = _
}
object TestBean {
def main(args: Array[String]): Unit = {
val m = new Manager("jack")
println("m=" + m)
}
}
4、包对象
基本介绍
包可以包含类、对象和特质trait,但不能包含函数/方法或变量的定义。这是Java虚拟机的局限。
为了弥补这一点不足,scala提供了包对象的概念来解决这个问题。
package com.ali {
//每个包都可以有一个包对象。你需要在父包(com.ali)中定义它,且名称与子包一样。
package object scala {
var name = "jack"
def sayOk(): Unit = {
println("package object sayOk!")
}
}
package scala {
class Test {
def test() : Unit ={
//这里的name就是包对象scala中声明的name属性
println(name)
//这个sayOk 就是包对象scala中声明的sayOk方法
sayOk()
}
}
object TestObj {
def main(args: Array[String]): Unit = {
val t = new Test()
t.test()
//因为TestObje和scala这个包对象在同一包,因此也可以使用name属性。
println("name=" + name)
}
}
}
}
二、包的可见性
1、Scala中包的可见性介绍
在Java中,访问权限分为: public,private,protected和默认。在Scala中,你可以通过类似的
修饰符达到同样的效果。但是使用上有区别。
示例代码:
package com.lj.scala.packagetest
/**
* @author Administrator
* @create 2020-03-10
*/
object PackTest01 {
def main(args: Array[String]): Unit = {
val p1 = new People01
p1.showInfo()
People01.test(p1)
}
}
class People01 {
var name = "Jack"
private var sal: Double = 999.89
def showInfo(): Unit = {
println("name=" + name + "--sal=" + sal)
}
}
object People01 {
def test(p: People01): Unit = {
// 这里体现出在伴生对象中,可以访问p.sal
println("test() name=" + p.name + " sal= " + p.sal)
}
}
=====================运行结果===========================
name=Jack--sal=999.89
test() name=Jack sal= 999.89
=====================运行结果===========================
2、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.lj.scala.packagetest
/**
* @author Administrator
* @create 2020-03-10
*/
object PackTest01 {
def main(args: Array[String]): Unit = {
val p2 = new People02
p2.showInfo()
}
}
class People02 {
var name = "Jack"
/**
* 增加包访问权限后
* 1.private同时起作用。不仅同类可以使用;
* 2. 同时com.lj.scala.packagetest中包下其他类也可以使用。
* /
private[packagetest] var sal: Double = 999.89
def showInfo(): Unit = {
println("p2: name=" + name + "--sal=" + sal)
}
}
=====================运行结果===========================
p2: name=Jack--sal=999.89
=====================运行结果===========================
三、包的引入
1、Scala引入包基本介绍
Scala引入包也是使用import, 基本的原理和机制和Java一样,但是Scala中的import功能更加强
大,也更灵活。
因为Scala语言源自于Java,所以java.lang包中的类会自动引入到当前环境中,而Scala中的
scala包和Predef包的类也会自动引入到当前环境中,即其下面的类可以直接使用。
如果想要把其他包中的类引入到当前环境中,需要使用import语言。
2、Scala引入包的细节和注意事项
1. 在Scala中,import语句可以出现在任何地方,并不仅限于文件顶部,import语句的作用一直
延伸到包含该语句的块末尾。这种语法的好处是:在需要时在引入包,缩小import 包的作用范
围,提高效率;
2. Java中如果想要导入包中所有的类,可以通过通配符*,Scala中采用下 _;
例如:import scala.collection.mutable._
3. 如果不想要某个包中全部的类,而是其中的几个类,可以采用选取器(大括号);
例如:import scala.collection.mutable.{HashMap, HashSet}
4. 如果引入的多个包中含有相同的类,那么可以将不需要的类进行重命名进行区分;
例如:import java.util.{ HashMap=>JavaHashMap, List}
import scala.collection.mutable._
var map = new HashMap() // 此时的HashMap指向的是scala中的HashMap
var map1 = new JavaHashMap(); // 此时使用的java中hashMap的别名
5. 如果某个冲突的类根本就不会用到,那么这个类可以直接隐藏掉。
// 含义为 引入java.util包的所有类,但是忽略HahsMap类。
import java.util.{ HashMap=>_, _}
// 此时的HashMap指向的是scala中的HashMap, 而且idea工具,的提示也不会显示java.util的
// HashMaple
var map = new HashMap()
四、面向对象编程方法-抽象
如何理解抽象
定义一个类时候,实际上就是把一类事物的共有的属性和行为提取出来,形成一个物理模型(模板),
这种研究问题的方法称为抽象。
基本介绍
面向对象编程有三大特征:封装、继承和多态。
《封装》
1、封装介绍
封装(encapsulation)就是把抽象出的数据和对数据的操作封装在一起,数据被保护在内部,程序的
其它部分只有通过被授权的操作(成员方法),才能对数据进行操作。
2、封装的理解和好处
隐藏实现细节
也可以对数据进行验证,保证安全合理
3、如何体现封装
对类中的属性进行封装
通过成员方法,包实现封装
4、封装的实现步骤
1. 将属性进行私有化;
2. 提供一个公共的set方法,用于对属性判断并赋值
def setXxx(参数名 : 类型) : Unit = {
//加入数据验证的业务逻辑
属性 = 参数名
}
3. 提供一个公共的get方法,用于获取属性的值
def getXxx() [: 返回类型] = {
return 属性
}
封装示例代码:
package com.lj.scala.packagetest
import scala.io.StdIn
/**
* @author Administrator
* @create 2020-03-10
*/
object PackTest02 {
def main(args: Array[String]): Unit = {
val p1 = new People03
var i = 0
var age: Int = 0
while (i < 3) {
print("请输入年龄:")
age = StdIn.readInt()
p1.setAge(age)
i += 1
}
}
}
class People03 {
var name: String = _
private var age: Int = 0
private var salary: Double = 0.00
def setAge(age: Int): Unit = {
if (age > 18 && age < 80) {
this.age = age
println("输入数值合理,可以进行查看!!!")
} else {
println("输入的数值不合理!!!")
}
}
}
=====================运行结果===========================
请输入年龄:13
输入的数值不合理!!!
请输入年龄:19
输入数值合理,可以进行查看!!!
请输入年龄:22
输入数值合理,可以进行查看!!!
=====================运行结果===========================
5、Scala封装的注意事项和细节
1. Scala中为了简化代码的开发,当声明属性时,本身就自动提供了对应setter/getter方法,如果
属性声明为private的,那么自动生成的setter/getter方法也是private的,如果属性省略访问权限修
饰符,那么自动生成的setter/getter方法是public的;
2. 因此我们如果只是对一个属性进行简单的set和get ,只要声明一下该属性(属性使用默认访问修
饰符) 不用写专门的get,set方法,默认会创建,访问时,直接对象.变量。这样也是为了保持访问
一致性;
3. 从形式上看p1.name 直接访问属性,其实底层仍然是访问的方法;
4. 有了上面的特性,目前很多新的框架,在进行反射时,也支持对属性的直接反射。
《继承》
1、继承基本介绍和示意图
继承可以解决代码复用,让我们的编程更加靠近人类思维.当多个类存在相同的属性(变量)和方法时,
可以从这些类中抽象出父类(比如Student),在父类中定义这些相同的属性和方法,所有的子类不需要
重新定义这些属性和方法,只需要通过extends语句来声明继承父类即可。
和Java一样,Scala也支持类的单继承。
Scala继承的基本语法
class 子类名 extends 父类名 { 类体 }
Scala继承示例代码:
package com.lj.scala.packagetest
/**
* @author Administrator
* @create 2020-03-10
*/
object PackTest03 {
def main(args: Array[String]): Unit = {
val stu01 = new Student04
// 子类Student04可以访问父类People04的属性和方法
stu01.name = "Leo"
stu01.showInfo("Jack", 22)
}
}
class People04 {
var name: String = _
var age: Int = _
def showInfo(name: String, age: Int): Unit = {
println("信息:name=" + name + ",age=" + age)
}
}
class Student04 extends People04 {
var id: Int = _
def play(message: String): Unit = {
println("他在玩王者荣耀!!!")
}
}
=====================运行结果===========================
信息:name=Jack,age=22
=====================运行结果===========================
Scala子类继承了什么,怎么继承了?
子类继承了所有的属性,只是私有的属性不能直接访问,需要通过公共的方法去访问。
2、重写方法
说明: scala明确规定,重写一个非抽象方法需要用override修饰符,调用超类的方法使用super关键字。
示例代码:
package com.lj.scala.packagetest
/**
* @author Administrator
* @create 2020-03-10
*/
object PackTest03 {
def main(args: Array[String]): Unit = {
val stu01 = new Student04
// 子类Student04可以访问父类People04的属性和方法
stu01.name = "Leo"
stu01.showInfo("Jack", 22)
}
}
class People04 {
var name: String = _
var age: Int = _
def showInfo(name: String, age: Int): Unit = {
println("信息:name=" + name + ",age=" + age)
}
def sayHello(): Unit = {
println("Say Hello!!!")
}
}
class Student04 extends People04 {
var id: Int = _
def play(message: String): Unit = {
println("他在玩王者荣耀!!!")
}
override def showInfo(name: String, age: Int): Unit = {
println("重写父类的方法!")
// 子类调用超类的方法使用super关键字
super.sayHello()
}
}
=====================运行结果===========================
重写父类的方法!
Say Hello!!!
=====================运行结果===========================
3、Scala中类型检查和转换
基本介绍
要测试某个对象是否属于某个给定的类,可以用isInstanceOf方法。用asInstanceOf方法将引用
转换为子类的引用。classOf获取对象的类名。
1. classOf[String]就如同Java的 String.class;
2. obj.isInstanceOf[T]就如同Java的obj instanceof T 判断obj是不是T类型;
3. obj.asInstanceOf[T]就如同Java的(T)obj 将obj强转成T类型。
示例代码:
package com.lj.scala.packagetest
/**
* @author Administrator
* @create 2020-03-10
*/
object PackTest04 {
def main(args: Array[String]): Unit = {
val stu01 = new Student05;
// 使用classOf获取类名
println("stu01的类名:" + classOf[Student05])
// 使用反射的机制获取类名
println("stu01的类名:" + stu01.getClass.getName)
// 测试isInstanceOf 与 asInstanceOf
var p01 = new People05("Jack", "男", 13)
p01.showInfo()
// 将子类引用给父类(向上转型,自动)
p01 = stu01
p01.showInfo()
// 将父类的引用重新转成子类引用(多态),即向下转型
val stu02 = p01.asInstanceOf[Student05]
stu02.showInfo()
}
}
class People05 {
var name: String = _
var sex: String = _
var age: Int = _
def this(name: String, sex: String, age: Int) {
this()
this.name = name
this.sex = sex
this.age = age
}
def showInfo(): Unit = {
println(s"show info:name=$name, sex=$sex, age=$age.")
}
}
class Student05 extends People05 {
var ID: Int = 1000010
def play(name: String, games: String): Unit = {
println(name + "在玩" + games)
}
}
=====================运行结果===========================
stu01的类名:class com.lj.scala.packagetest.Student05
stu01的类名:com.lj.scala.packagetest.Student05
show info:name=Jack, sex=男, age=13.
show info:name=null, sex=null, age=0.
show info:name=null, sex=null, age=0.
=====================运行结果===========================
4、Scala中超类的构造
回顾-Java中超类的构造
示例代码:
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()
System.out.println("B()");
}
public B(String name) {
super(name); // 调用父类的构造器
System.out.println("B(String name)" + name);
}
}
说明:
从代码可以看出:在Java中,创建子类对象时,子类的构造器总是去调用一个父类的构造
器(显式或者隐式调用)。
Scala超类的构造说明
1. 类有一个主构器和任意数量的辅助构造器,而每个辅助构造器都必须先调用主构造器(也可以是
间接调用);
示例代码:
class Person {
var name = "Jack"
println("Person...")
}
class Emp extends Person {
println("Emp ....")
def this(name : String) {
this // 必须调用主构造器
this.name = name
println("Emp 辅助构造器~")
}
}
2. 只有主构造器可以调用父类的构造器。辅助构造器不能直接调用父类的构造器。在Scala的
构造器中,不能调用super(params);
示例代码:
class Person(name: String) { //父类的构造器
}
class Emp (name: String) extends Person(name) {
// 将子类参数传递给父类构造器,这种写法√
// 可以将子类的参数name传递给父类的name
// super(name) (×) 没有这种语法
def this() {
super("abd") // (×)不能在辅助构造器中调用父类的构造器
}
}
5、覆写字段
基本介绍
在Scala中,子类改写父类的字段,我们称为覆写/重写字段。覆写字段需使用override修饰。
回顾
在Java中只有方法的重写,没有属性/字段的重写,准确的讲,是隐藏字段代替了重写。
原因:
这个主要涉及到java里面一个字段隐藏的概念,父类和子类定义了一个同名的字段,不会报错。
但对于同一个对象,用父类的引用去取值(字段),会取到父类的字段的值,用子类的引用去取值(
字段),则取到子类字段的值。在实际的开发中,要尽量避免子类和父类使用相同的字段名,否则
很容易引入一些不容易发现的bug。
回顾-Java另一重要特性: 动态绑定机制
1. 当调用对象方法的时候,该方法会和该对象的内存地址绑定;
2. 当调用对象属性时,没有动态绑定机制,哪里声明,那里使用。
示例代码:
package com.lj.scala.packagetest;
/**
* @author Administrator
* @create 2020-03-10
*/
public class JavaDaynamicBind {
public static void main(String[] args) {
/**
* 1. 当调用对象方法的时候,该方法会和该对象的内存地址绑定;
* 2. 当调用对象属性时,没有动态绑定机制,哪里声明,那里使用。
*/
AA aa = new BB();
System.out.println("值:" + aa.sum()); // 40 --> 屏蔽子类BB中的sum方法 // 30
System.out.println("值:" + aa.sum1()); // 30 --> 屏蔽子类BB中的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 sum() {
return i + 20;
}
*/
public int getI() {
return i;
}
/*
public int sum1() {
return i + 10;
}
*/
}
Scala覆写字段注意事项
1. def只能重写另一个def(即:方法只能重写另一个方法);
2. val只能重写另一个val属性或重写不带参数的def;
3. var只能重写另一个抽象的var属性
示例代码:
package com.lj.scala.packagetest
/**
* @author Administrator
* @create 2020-03-10
*/
object PackTest06 {
def main(args: Array[String]): Unit = {
}
}
class SmallCar {
var name: String = _
val color: String = "黑色"
def run(): String = {
println("running......")
"running......"
}
def info(name: String): Unit ={
println("这个车开起来很舒服!")
}
}
class SmallBMW extends SmallCar {
// 重写val属性
override val color: String = "白色"
// 重写不带参数的def run()
override def run(): String = "跑的飞快!!!"
// 带参数的def重写
override def info(name: String): Unit = {
println("这个车开起来很省油")
}
}
// var只能重写另一个抽象的var属性
abstract class A01 {
// 抽象属性:声明未初始化的变量就是抽象的属性,抽象属性在抽象类中
var name: String // 抽象属性
}
class B01 extends A01{
/**
* 说明:
* 1. 如果我们在子类中去重写父类的抽象属性,本质是实现了抽象方法;
* 2. 因此我们也可写override,也可以不写。
*/
override var name: String = "金毛"
override var age: Int = 2
}
/**
* var重写抽象的var属性小结:
* 1.一个属性没有初始化,那么这个属性就是抽象属性;
* 2.抽象属性在编译成字节码文件时,属性并不会声明,但是会自动生成抽象方法,所以类必须
* 声明为抽象类;
* 3.如果是覆写一个父类的抽象属性,那么override关键字可省略 [原因:父类的抽象属性,
* 生成的是抽象方法,因此就不涉及到方法重写的概念,因此override可省略].
*/
6、抽象类
基本介绍
在Scala中,通过abstract关键字标记不能被实例化的类。方法不用标记abstract,只要省掉方
法体即可。抽象类可以拥有抽象字段,抽象字段/属性就是没有初始值的字段;
抽象类基本语法
示例代码:
abstract class Person() { // 抽象类
var name: String // 抽象字段, 没有初始化
def printName // 抽象方法, 没有方法体
}
说明:
抽象类的价值更多是在于设计,是设计者设计好后,让子类继承并实现抽象类(即:实现抽象
类的抽象方法)
Scala抽象类使用的注意事项和细节
1. 抽象类不能被实例;
2. 抽象类不一定要包含abstract方法。也就是说,抽象类可以没有abstract方法;
3. 一旦类包含了抽象方法或者抽象属性,则这个类必须声明为abstract;
4. 抽象方法不能有主体,不允许使用abstract修饰;
5. 如果一个类继承了抽象类,则它必须实现抽象类的所有抽象方法和抽象属性,除非它自己
也声明为abstract类;
6. 抽象方法和抽象属性不能使用private、final 来修饰,因为这些关键字都是和重写/实现相违背的;
7. 抽象类中可以有实现的方法;
8. 子类重写抽象方法不需要override,写上也不会错。
7、匿名子类
基本介绍
和Java一样,可以通过包含带有定义或重写的代码块的方式创建一个匿名的子类。
回顾-java匿名子类使用
package com.lj.scala.packagetest;
/**
* @author Administrator
* @create 2020-03-10
*/
public class NoNameTest {
public static void main(String[] args) {
// 创建一个匿名子类对象
A05 a05 = new A05() {
@Override
public void cry() {
System.out.println("cry....");
}
};
a05.cry();
}
}
abstract class A05 {
abstract public void cry();
}
=====================运行结果===========================
cry....
=====================运行结果===========================
scala匿名子类示例代码:
package com.lj.scala.packagetest
/**
* @author Administrator
* @create 2020-03-10
*/
object ScalaNoName {
def main(args: Array[String]): Unit = {
val monster = new Monster {
override var name: String = "白骨精"
override def cry(): Unit = {
println(name + "嗷嗷叫!!!")
}
}
monster.cry()
}
}
abstract class Monster {
// 抽象属性
var name: String
// 抽象方法
def cry()
}
=====================运行结果===========================
白骨精嗷嗷叫!!!
=====================运行结果===========================
对以前的知识回顾,加深基础知识!
学习来自:北京尚硅谷韩顺平老师—尚硅谷大数据技术之Scala
每天进步一点点,也许某一天你也会变得那么渺小!!!