• Scala基础【模板方法设计模式、基础面向对象编程】


    一 模板方法的设计模式

    基本原理:根据一个模板做出一个东西,但是细节有轻微差别

    逻辑没有变化,抽象类也没有变化,重点是用哪具体的类,这种代码的写法叫做模板方法的设计模式。父类将算法的骨架搭建好,子类只需要实现具体的细节即可。在执行时,只需要创建不同的子类就可以完成不同的功能。

    以下代码用到的功能有:多态,方法的重写

    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");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    使用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")
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    二 基础面向对象编程

    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    1 包

    (1)java中package的作用

    • 分类管理(X)
      • 工具类 – util包 – util.StringUtil , util.DateUtil
        • 主要用.后面的,包名并不重要
      • 通用类 – common包
      • 实体类 – bean包
    • 区分相同名称的类(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
      
      • 1

      等同于

      package com
      package hike
      package bigdata
      package scala
      package chapter06
      
      • 1
      • 2
      • 3
      • 4
      • 5
    • 源码的物理路径和包名没有关系

      package com
      package hike
      package bigdata
      package scala
      package chapter07
      
      • 1
      • 2
      • 3
      • 4
      • 5

      写错也没有关系,可以正常运行

    • 明确包的作用域,可以在package的后面添加大括号,体现包之间的父子关系,java中的包名之间的.表示调用,没有父子关系

      package com
      package hike
      package bigdata
      package scala {
        package chapter06 {
          object Scala01_Object_Package {
            def main(args: Array[String]): Unit = {
              println("anythings")
            }
          }
        }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
    • 同一个源码中,子包可以直接访问父包中的内容

      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()
            }
          }
        }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
    • scala可以将包当成对象来用,可以直接声明属性和方法,在包对象中声明的属性和方法,在这个包下其他类中可以直接使用

    2 导入

    (1)java中import的功能

    • 导入其他包中的类
      • 若没有包,则不需要导类了
    • 静态导入
      • 当父类和子类存在同名方法,静态导入会引起歧义

    (2)scala中import的功能

    在java中,import功能比较单一,但是不能省略,所以import在scala中被赋予了更多的功能

    • 星号在scala中有特殊用途,所以不能使用在import语法中,需要用特殊的符号下划线代替星号

      import java.util._
      
      • 1
    • import关键字可以在任何地方使用

      import java.util.Date
      new Date()
      
      • 1
      • 2
    • 可以在一行中导入同一个包中的多个类

      import java.util.{ArrayList,List,LinkedList}
      new ArrayList()
      
      • 1
      • 2
    • 导包,对应于package中的包对象,则以下语句可以理解为把一个util对象导入了进来

      import java.util
      new util.ArratList()
      
      • 1
      • 2
          import java.util._
          import java.sql._
          new Date()
          new util.ArrayList()
          new Timestamp(111)
      
      • 1
      • 2
      • 3
      • 4
      • 5

      出现错误,一个类被导入了两次,则有了隐藏类

      it is imported twice in the same scope by
      import java.sql._
      and import java.util._
          new Date()
      
      • 1
      • 2
      • 3
      • 4
    • 隐藏类,遇到Date类屏蔽它,不运行

          import java.util._
          import java.sql.{Date=>_,_}
          new Date()
          new util.ArrayList()
          new Timestamp(111)
      
      • 1
      • 2
      • 3
      • 4
      • 5
    • 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{
          }
        }
      }
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
    • 给类起别名

          import java.util.{HashMap=>JavaHashMap}
          println(new JavaHashMap())
      
      • 1
      • 2

    (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{
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    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
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    使用val声明的类的变量,在编译时会给属性添加final关键字,编译器不会提供属性的set方法,取值不能修改,以上两句反编译为

    private String name = "zhangsan"
    private final int age = 30
    
    • 1
    • 2

    scala中变量必须显式的初始化,如果希望类的属性和java一样由系统进行初始化,而不是手动赋值,所以采用特殊符号,下划线。

    var email : String = _
    
    • 1

    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()
    
    • 1
    • 2
    • 3
    • 4

    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{
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    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();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    此时,方法的提供者为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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    在本报外部定义类,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
    • 4
    • 5
    • 6
    • 7
    • 8

    在别的包下定义类1,2,3 不能使用

  • 相关阅读:
    38-数组 _ 一维数组
    LabVIEW工业虚拟仪器的标准化实施
    恒生电子,快手25届实习内推
    CentOS遇到的麻烦与解决方案
    Gmail发送邮件的配置方法
    开发必备工具
    面试官:什么是伪共享,如何避免?
    iOS 13.0 暗黑模式的适配
    mvc-ioc实现
    网页编程入门应该首先学些什么
  • 原文地址:https://blog.csdn.net/weixin_43923463/article/details/125898428