概述
文章目录
- 五、函数式编程
- 5.1 函数基础
- 六、面向对象
- 6.1 包
- 6.2 类
- 6.3 特质
五、函数式编程
面向对象编程,对象的本质:对数据和行为的一个封装
- 解决问题,分解对象,行为,属性,然后通过对象的关系以及行为的调用来解决问题
- 对象:用户
- 行为:登录
- 属性:用户名、密码
5.1 函数基础
函数和方法的区别
类中的函数称之方法。
- 函数声明在方法体中,方法声明在类中方法外。
- 函数没有重载和重写的概念;方法可以进行重载和重写
- 任意地方都可以定义一段有功能的代码,那我们定义出来以后,就是狭义上的函数;
- 方法必须定义在类或者Object下面,不能放在方法里面去定义
object TestFunction {
// (2)方法可以进行重载和重写,程序可以执行
def main(): Unit = {
}
def main(args: Array[String]): Unit = {
// (1)Scala 语言可以在任何的语法结构中声明任何的语法
import java.util.Date
new Date()
// (2)函数没有重载和重写的概念,程序报错
def test(): Unit ={
println("无参,无返回值")
}
test()
def test(name:String):Unit={
println()
}
//(3)Scala 中函数可以嵌套定义
def test2(): Unit ={
def test3(name:String):Unit={
println("函数可以嵌套定义")
}
}
}
}
函数参数
(1)可变参数
(2)如果参数列表中存在多个参数,那么可变参数一般放置在最后
(3)参数默认值,一般将有默认值的参数放置在参数列表的后面
(4)带名参数
object TestFunction {
def main(args: Array[String]): Unit = {
// (1)可变参数
def test( s : String* ): Unit = {
println(s)
}
// 有输入参数:输出 Array
test("Hello", "Scala")
// 无输入参数:输出 List()
test()
// (2)如果参数列表中存在多个参数,那么可变参数一般放置在最后
def test2( name : String, s: String* ): Unit = {
println(name + "," + s)
}
test2("jinlian", "dalang")
// (3)参数默认值
def test3( name : String, age : Int = 30 ): Unit = {
println(s"$name, $age")
}
// 如果参数传递了值,那么会覆盖默认值
test3("jinlian", 20)
// 如果参数有默认值,在调用的时候,可以省略这个参数
test3("dalang")
// 一般情况下,将有默认值的参数放置在参数列表的后面
def test4( sex : String = "男", name : String ): Unit = {
println(s"$name, $sex")
}
// Scala 函数中参数传递是,从左到右
//test4("wusong")
//(4)带名参数,适用于有默认参数值的方法
test4(name="ximenqing")
}
}
六、面向对象
Scala 的面向对象思想和 Java 的面向对象思想和概念是一致的。
Scala 中语法和 Java 不同,补充了更多的功能。
6.1 包
在处理程序,尤其是大型程序时,减少耦合是很重要的。所谓的耦合,指的是程序不同部分依赖其他部分的程度。低耦合能减少程序某个看似无害的改动对其他部分造成严重后果的风险。减少耦合的一种方式是以模块化的风格编写代码。你可以将程序切割为若干个较小的模块,每个模块都有所谓的内部和外部之分。
Scala 有两种包的管理风格,一种方式和 Java 的包管理风格相同,每个源文件一个包(包名和源文件所在路径不要求必须一致),包名用“.”进行分隔以表示包的层级关系,如com.company.scala。另一种风格,通过嵌套的风格表示层级关系,如下
package com{
package company{
package scala{
}
}
}
第二种风格有以下特点:
(1)一个源文件中可以声明多个 package
(2)子包中的类可以直接访问父包中的内容,而无需导包
包对象
在 Scala 中可以为每个包定义一个同名的包对象,定义在包对象中的成员,作为其对
应包下所有 class 和 object 的共享变量,可以被直接访问。
- 若使用 Java 的包管理风格,则包对象一般定义在其对应包下的 package.scala 文件中,包对象名与包名保持一致。
导包说明
1)和 Java 一样,可以在顶部使用 import 导入,在这个文件中的所有类都可以使用。
2)局部导入:什么时候使用,什么时候导入。在其作用范围内都可以使用
3)通配符导入:import java.util._
4)给类起名:import java.util.{ArrayList=>JL}
5)导入相同包的多个类:import java.util.{HashSet, ArrayList}
6)屏蔽类:import java.util.{ArrayList=>,}
7)导入包的绝对路径:new root.java.util.HashMap
注意Scala 中的三个默认导入分别是
import java.lang._
import scala._
import scala.Predef._
6.2 类
-
回顾java中,如果是public向外公开的,那么必须和文件名一致,也只能有一个。不写访问修饰符则可以定义多个,包访问权限。
-
scala中没有public关键字,默认就是公有,不能加public,一个文件可以写多个类,不要求和文件名一致。
-
访问修饰符可以是:private protected private [pacakgeName],默认就是公有,不需要加。
-
成员如果需要Java
Bean规范的getter和setter的话可以加@scala.beans.BeanProperty相当于自动创建,不需要显式写出。 -
成员给初值_会赋默认值,scala中定义变量必须赋值,可以这样做。值类型的值0,引用则是null。定义常量的话不能用_,因为只能初始化一次,编译器会提示。
封装:
- Java的封装:私有化,提供getter和setter。
scala中考虑到Java太冗余了,脱裤子放屁一样。scala中的公有属性,底层实际为private,并通过get方法obj.field()和set方法obj.field_=(value)对其进行操作。所以scala不推荐设置为private。如果需要和其他框架互操作,必须提供JavaBean规范的getter和setter的话可以加@scala.beans.BeanProperty注解。
访问权限**
- Java中private protected public和默认包访问权限。
- scala中属性和方法默认公有,并且不提供public关键字。
- private私有,类内部和伴生对象内可用。
- protected保护权限,scala中比java中严格,只有同类、子类可访问,同包无法访问。
- private [pacakgeName]增加包访问权限,在包内可以访问。
构造器
包括主构造器和辅助构造器。
class 类名(形参列表) { // 主构造器
// 类体
def this(形参列表) { // 辅助构造器
}
def this(形参列表) { //辅助构造器可以有多个...
}
}
object Constructor {
def main(args: Array[String]): Unit = {
val p: Person = new Person()
p.Person() // call main constructor
val p1 = new Person("alice")
val p2 = new Person("bob", 25)
p1.Person()
}
}
class Person {
var name: String = _
var age: Int = _
println("call main construtor")
def this(name: String) {
this()
println("call assist constructor 1")
this.name = name
println(s"Person: $name $age")
}
def this(name: String, age: Int) {
this(name)
this.age = age
println("call assist constructor 2")
println(s"Person: $name $age")
}
// just a common method, not constructor
def Person(): Unit = {
println("call Person.Person() method")
}
}
- 主构造器写在类定义上,一定是构造时最先被调用的构造器,方法体就是类定义,可以在类中方法定义的同级编写逻辑,都是主构造器一部分,按顺序执行。
- 辅助构造器用this定义。
- 辅助构造器必须直接或者间接调用主构造器,调用其他构造必须位于第一行。
- 主构造器和辅助构造器是重载的方法,所以参数列表不能一致。
- 可以定义和类名同名方法,就是一个普通方法。
主构造器中形参三种形式:不使用任何修饰,var修饰,val修饰
- 不使用任何修饰那就是一个形参,但此时在类内都可以访问到这个变量。逻辑上不是一个成员(报错信息这么写),但是可以访问
- 使用var、val修饰那就是定义为类成员,分别是变量和常量,不需要也不能在类内再定义一个同名字段。调用时传入参数就直接给到该成员,不需要再显式赋值。
- 主构造器中的var val成员也可以添加访问修饰符。
- 不加参数列表相当于为空,()可以省略。
- 主构造器的访问修饰符添加到参数列表()前。
实践指南:
推荐使用scala风格的主构造器var val修饰参数的编写方法,而不要被Java毒害!
如果需要多种重载的构造器那么就添加新的的辅助构造器。
继承 - class ChildClassName[(argList1)] extends BaseClassName[(args)] { body }
- 子类继承父类属性和方法。
- 可以调用父类构造器,但感觉好像很局限,子类中只可能调用到主构造或者辅助构造中的其中一个构造器。
抽象类
- 抽象属性:val/var name: Type,不给定初始值。
- 抽象方法:def methodName(): RetType,只声明不实现。
- 子类如果没有覆写全部父类未定义的属性和方法,那么就必须定义为抽象类。老生常谈了。
- 重写非抽象方法属性必须加override,重写抽象方法则可以不加override。
- 子类调用父类中方法使用super关键字。
- 子类重写父类抽象属性,父类抽象属性可以用var修饰,val var都可以。因为父类没有实现嘛,需要到子类中来实现。
- 如果是重写非抽象属性,则父类非抽象属性只支持val,不支持var。因为var修饰为可变量,子类继承后可以直接使用修改,没有必要重写。val不可变才有必要重写。
- 实践建议是重写就加override,都是很自然的东西,理解就好,不必纠结于每一个细节。
6.3 特质
特质是Scala代码复用的基础单元。特质将方法和字段封装起来,然后通过将它们混入类的方式来实现复用。它不同于继承,类继承要求每个类都继承一个明确的父类,而类可以同时混入任意数量的特质。
引入/混入(mixin)特征:
有父类class extends baseClass with trait1 with trait2 ... {}
没有父类class extends trait1 with trait2 ... {}
- 其中可以定义抽象和非抽象的属性和方法。
- 匿名子类也可以引入特征。
- 特征和基类或者多个特征中重名的属性或方法需要在子类中覆写以解决冲突,最后因为动态绑定,所有使用的地方都是子类的字段或方法。属性的话需要类型一致,不然提示不兼容。方法的话参数列表不一致会视为重载而不是冲突。
- 如果基类和特征中的属性或方法一个是抽象的,一个非抽象,且兼容,那么可以不覆写。很直观,就是不能冲突不能二义就行。
- 多个特征和基类定义了同名方法的,就需要在子类重写解决冲突。其中可以调用父类和特征的方法,此时super.methodName指代按照顺序最后一个拥有该方法定义的特征或基类。也可以用super[baseClassOrTraitName].methodName直接指代某个基类的方法,注意需要是直接基类,间接基类则不行。
- 也就是说基类和特征基本是同等地位。
最后
以上就是飞快西牛为你收集整理的【博学谷学习记录】超强总结,用心分享丨大数据超神之路(二):高级特性的全部内容,希望文章能够帮你解决【博学谷学习记录】超强总结,用心分享丨大数据超神之路(二):高级特性所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复