文章目录
一 模板方法的设计模式
基本原理:根据一个模板做出一个东西,但是细节有轻微差别
逻辑没有变化,抽象类也没有变化,重点是用哪具体的类,这种代码的写法叫做模板方法的设计模式。父类将算法的骨架搭建好,子类只需要实现具体的细节即可。在执行时,只需要创建不同的子类就可以完成不同的功能。
以下代码用到的功能有:多态,方法的重写
package com.hike.bigdata.scala.test;
public class TestParent {
public static void main(String[] args) {
Parent parent = new QueryChild();
parent.doExecute();
Parent parent1 = getParent();
parent1.doExecute();
}
private static Parent getParent(){
return new OperChild();
}
}
abstract class Parent{
public void execute(){
startTransaction();
doExecute();
endsTransaction();
}
public void startTransaction(){
System.out.println("startTransaction");
}
public void endsTransaction(){
System.out.println("endsTransaction");
}
//不同的sql语句使用不同的操作,所以将其设置为抽象方法
abstract public void doExecute();
}
class QueryChild extends Parent{
@Override
public void doExecute() {
System.out.println("do execute query");
}
}
class OperChild extends Parent{
@Override
public void doExecute() {
System.out.println("do execute insert/update/delete");
}
}
使用scala实现模板方法的设计模式,无抽象类,无子类
package com.hike.bigdata.scala.test
object TestTemplatMethodScala {
def main(args: Array[String]): Unit = {
TM.execute{
println("do execte insert")
}
TM.execute{
println("do execte update")
}
}
object TM{
def execute(op : => Unit ): Unit = {
startTransaction()
op
endsTransaction()
}
def startTransaction(): Unit = {
System.out.println("startTransaction")
}
def endsTransaction(): Unit = {
System.out.println("endsTransaction")
}
}
}
二 面向对象编程
java中面向对象代码的基本语法操作:package,import,创建类,类中创建属性和方法,如果与别的类有关系,可以将别的类当做本类的属性,构建对象,访问对象中的方法,如果静态方法,也可以通过类名访问。
同样,scala中面向对象的基本语法也大体是这些内容。
/**
* package xxx.yyy.zzz
* import java.util.List
*
* public class Test{
* private String name;
* public void setName(){};
* }
*
* Test test = new Test();
* test.setName();
*/
1 包
(1)java中package的作用
- 分类管理(X)
- 工具类 – util包 – util.StringUtil , util.DateUtil
- 主要用.后面的,包名并不重要
- 通用类 – common包
- 实体类 – bean包
- 工具类 – util包 – util.StringUtil , util.DateUtil
- 区分相同名称的类(X)
- 如java.util.Date 和 java.sql.Date
- 但如果给这两个类重新起名,包名也就不重要了,java.util.UtilDate 和 java.sql.SqlDate
- 包访问权限(X)
- 大家都不用,好像不是很重要,可以去掉
(2)scala中package的作用
在java中package语法过于简单,但是scala基于java开发,不能够省略,所以scala中给package更加重要的功能
-
可以在源码文件中多次使用package关键字
package com.hike.bigdata.scala.chapter06
等同于
package com package hike package bigdata package scala package chapter06
-
源码的物理路径和包名没有关系
package com package hike package bigdata package scala package chapter07
写错也没有关系,可以正常运行
-
明确包的作用域,可以在package的后面添加大括号,体现包之间的父子关系,java中的包名之间的.表示调用,没有父子关系
package com package hike package bigdata package scala { package chapter06 { object Scala01_Object_Package { def main(args: Array[String]): Unit = { println("anythings") } } } }
-
同一个源码中,子包可以直接访问父包中的内容
package com.hike.bigdata.scala.chapter06 package com package hike package bigdata package scala { class Test{ def test(): Unit ={ println("test...") } } package chapter06 { object Scala01_Object_Package { def main(args: Array[String]): Unit = { new Test().test() } } } }
-
scala可以将包当成对象来用,可以直接声明属性和方法,在包对象中声明的属性和方法,在这个包下其他类中可以直接使用
2 导入
(1)java中import的功能
- 导入其他包中的类
- 若没有包,则不需要导类了
- 静态导入
- 当父类和子类存在同名方法,静态导入会引起歧义
(2)scala中import的功能
在java中,import功能比较单一,但是不能省略,所以import在scala中被赋予了更多的功能
-
星号在scala中有特殊用途,所以不能使用在import语法中,需要用特殊的符号下划线代替星号
import java.util._
-
import关键字可以在任何地方使用
import java.util.Date new Date()
-
可以在一行中导入同一个包中的多个类
import java.util.{ArrayList,List,LinkedList} new ArrayList()
-
导包,对应于package中的包对象,则以下语句可以理解为把一个util对象导入了进来
import java.util new util.ArratList()
import java.util._ import java.sql._ new Date() new util.ArrayList() new Timestamp(111)
出现错误,一个类被导入了两次,则有了隐藏类
it is imported twice in the same scope by import java.sql._ and import java.util._ new Date()
-
隐藏类,遇到Date类屏蔽它,不运行
import java.util._ import java.sql.{Date=>_,_} new Date() new util.ArrayList() new Timestamp(111)
-
scala中导入类的操作,是以当前包路径的相对路径方式导入的,如果想使用绝对路径的方式,需要增加特殊操作,前面添加下划线root下划线.
在java中,HashMap打印出来是{k = v, k = v},ArrayList是[a, b, c]
package com.hike.bigdata.scala.chapter06 object Scala01_Object_import { def main(args: Array[String]): Unit = { println(new _root_.java.util.HashMap()) } } package java{ package util{ class HashMap{ } } }
-
给类起别名
import java.util.{HashMap=>JavaHashMap} println(new JavaHashMap())
(3)类加载的双亲委派机制
java中的三个类加载器:
- 启动类加载器(java的核心类库)由c语言开发
- 扩展类加载器(java的扩展类库)由java开发
- 应用类加载器(java的classpath中的类)由java开发
当自定义一个类,包名和类名都和java原生的类相同,如java.lang.String,当需要导入这个类时会导入java的String类,而不会导入自定义的类。因为String类中有其他类使用的各种方法,但是自定义的类并没有,会使其他的类也不能执行,称为“污染”,如果自定义的类和java的类产生冲突,选择哪一个,这时就会启动双亲委派机制。
首先,需要判断当前的类属于什么类,如为classpath中的类,则需要使用应用类加载器去加载,为了防止冲突,不会马上由应用类加载器去加载,会委派上一层的扩展类加载器加载,观察是否可以加载到这个类,当扩展类加载器收到请求时,为了防止冲突,同样会委派启动类加载器去加载,之后,它会在java的核心类库中查找这个类,如果找到会将其放到方法区内存当中,可以直接使用;找不到,会向下一级返回null,表示没有找到,之后扩展类加载器会在java的扩展类库中查找,加载到直接使用,加载不到,会抛出异常,应用类加载器会尝试捕获这个异常,尝试在类路径中查找这个类,找到可以直接使用,找不到将异常抛给java虚拟机,异常叫做ClassNotFoundException。
3 类
使用class关键字可以声明类,通过new的方式构造类的对象
java中一个源码文件中的公共类(类名和文件名完全相同)只能有一个,scala中没有这种约束
scala中的源码可以声明多个类,且可以声明多个公共类,名称可以和文件不一样
package com.hike.bigdata.scala.chapter06
object Scala04_Object_Class {
def main(args: Array[String]): Unit = {
val test = new Test()
}
class Test{
}
}
class A{
}
class B{
}
class C{
}
4 属性
所谓的属性就是类中的变量,在编译时,编译器会将变量编译为类的私有的属性,同时编译出公共的方法,功能就是对应的set,get方法
给类的属性赋值,等同于调用对象属性的set方法
访问类的属性时,等同于调用对象属性的get方法
def main(args: Array[String]): Unit = {
val test = new Test()
print(test.name)
test.name = "lisi"
println(test.name)
}
class Test{
var name : String = "zhangsan"
val age : Int = 30
}
使用val声明的类的变量,在编译时会给属性添加final关键字,编译器不会提供属性的set方法,取值不能修改,以上两句反编译为
private String name = "zhangsan"
private final int age = 30
scala中变量必须显式的初始化,如果希望类的属性和java一样由系统进行初始化,而不是手动赋值,所以采用特殊符号,下划线。
var email : String = _
java bean规范:属性私有化,提供set,get方法,两方法必须以set或get开头
这种要求主要与反射有关,反射一般用于架构设计,架构设计的目的就是通用化
比如想使用sql语句获得某一类的id,name,age值,如果方法没有规则,不方便取出这些值
sql => cols => [id,name,age] => getId, getName, getAge
scala中给属性提供的set,get方法不遵循bean规范,那么就不能再架构中使用,所以scala做了一些妥协,添加注解就会出现set,get方法
@BeanProperty var email : String = _
test.setEmail("XXX")
test.getEmail()
5 访问权限
所谓的访问权限,其实就是权利和限制,指的是方法的调用者和方法的提供者的关系
(1)java中的访问权限
- private: 本类
- default: 本类,本包
- protected: 本类,本包,子类
- public: 任意
package com.hike.bigdata.scala.test;
public class TestAccess {
public static void main(String[] args) {
Object aa = new AA();
aa.clone()
}
}
class AA{
}
Object类中clone方法的权限为protected,但在上述代码中却不能够使用
方法的提供者:java.lang.Object
方法的调用者:是com.hike.bigdata.scala.Test.TestAccess而不是com.hike.bigdata.scala.Test.AA
.的含义就是“的”,英语为“with”,表示从属关系
两者不同类,不同包,不属于父子类
这里要注意:TestAccess与Object有父子关系,但TestAccess与AA的Object没有父子关系,aa.clone()表示TestAccess想调用AA的Object的clone(),当然不能使用!
note:super在编译时存在,在运行时不存在且由多态可知,子类对象可以指向父类,意味着每一个子类对象的父类应该在自己的那块内存中,不同类的同名父类在不同类内部都存在
在AA类中重写clone方法
package com.hike.bigdata.scala.test;
public class TestAccess {
public static void main(String[] args) throws CloneNotSupportedException {
AA aa = new AA();
aa.clone();
}
}
class AA{
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
此时,方法的提供者为com.hike.bigdata.scala.Test.AA,方法的调用者为com.hike.bigdata.scala.Test.TestAccess,不同类,同包,所以aa可以使用clone
(2)scala中的访问权限
- private:同类
- private[包名]:同包,包私有
- protected:受保护的,同类和子类,没有同包
- (default) :什么都不写就是公共的,没有public关键字
本类都可以使用
package com.hike.bigdata.scala.chapter06
object Scala06_Object_Access {
def main(args: Array[String]): Unit = {
class Test{
private val name1:String = "zhangsan"
private[chapter06] val name2:String = "zhangsan"
protected val name3:String = "zhangsan"
val name4:String = "zhangsan"
def test(): Unit ={
println(name1)
println(name2)
println(name3)
println(name4)
}
}
}
}
在本报外部定义类,1,3 不能使用
class OuterTest{
def test(): Unit ={
val t = new Test();
println(t.name1)
println(t.name2)
println(t.name3)
println(t.name4)
}
在别的包下定义类1,2,3 不能使用