Scala面向对象要点总结

为什么scala号称万物皆对象?

1、 面向对象编程

scala面向对象的思想和java基本上是一致的。

1.1包 -package

  • java中的包
-- 包
     --1. 声明包(起名):域名反写 + 项目名称 + 模块名 + 程序类型名称
        a、什么是域名:www.baidu.com --> baidu.com是域名,www不是域名,所以域名反写为:com.baidu
        b、程序类型名称:比如util(工具)、core(核心)、test(测试)等包
        c、但是在实际的使用过程中,我们基本上是不太关注包名,所以怎么简单怎么来,导致我们在看别人的代码时就会出现下面这种包名:" c.a.b.s.bean.JavaUser06"
       
     -- 2. 包的作用
	   2.1 管理类:将声明的类分门别类的管理起来
      		-- 我们现在通过类名也可以看出来类的作用,所以管理类的作用就没那么重要,如下:
                  service.UserService => UserService
                  bean.JavaUser06  => BeanJavaUser06
      
       2.2 区分类 :依靠包名进行区分,也没那么重要了,如Date
               java.sql.Date => SQLDate
               java.util.Date => UtilDate
      
       2.3 类的访问权限:因为我们不能很好的使用4种管理权限,基本就是public private,所以也就没那么重要了;
        	
       2.4 编译类:类的源码程序应该和所在的包名保持一致 --> 这是java的限制
     
    -- 3. 总结:Java语法中,package包语法的作用没有那么强大。所以Scala语言对package语法进行了功能的补充,更加强大。       	   
  • Scala中的包
   -- 1. package和源码文件的物理路径没有关系
         a、scala会按照package的声明编译指定路径的class
   		 b、当前类编译后会在最后的package所在的包中生成class文件
  
  -- 2. package关键字可以多次声明
          a、识别时是自上而下的层级关系。
   
   -- 3. package可以使用层级结构
          a、在package包名的后面增加大括号,设定作用域范围以及层级关系
          b、子包可以直接访问父包中的内容,无需import导入 -- 在同一源码文件中才有效
             
    -- 4. 包也可以当成对象来使用
          a、package中为了和java兼容,默认不能声明属性和函数(方法),声明类是可以的。
          b、scala提供了一种特殊的对象声明方式: 包对象,"可以将一个包中共通性的方法或属性在包对象中声明。"
          c、一个包只能创建一个包对象;
          d、在包对象中的方法、属性和类可以被包中所有的类使用。
                       

1.2 导入 - import

  • java中的导入
	--1. 导类,不是导包
	--2. import static 静态导入,导入类的静态属性和静态方法
  1. java语法中import操作功能比较单一。但是不能舍弃
  2. Scala语言在java语法基础上进行扩展。
  • scala中的导入
	 -- 1. import 可以声明在任意的位置
            import java.sql.Date
            val date = new Date()

     -- 2. java中默认导入java.lang包中的类
           scala中默认导入的类:
               2.1  java.lang包中所有的类
               2.2  scala包中的类
               2.3  Predef (类似于java中静态导入)

       -- 3. Scala中的import可以导包
              import java.sql
              val date = new sql.Date();

       -- 4. 导入一个包中所有的类
          	 a、scala中使用"下划线"代替java中的星号
            	 import java.util.*; -- java方式
             b、上面这种方式会将util包下所有的类加载到方法区吗?
                不会,方法区的空间也是有限的,编译器会根据在类中使用了哪个类,会将导包的类进行转换,加载使用到的类。
                 import java.util._  -- scala中使用下划线代替java中星号,表示当前包下的所有类都要

       -- 5. 可以在一行中导入同一个包的多个类。使用一对{}花括号,将需要导入的类写在里面
             import java.util.{ArrayList, HashMap}
                 new ArrayList()
                 new HashMap()

 	   -- 6. 使用import关键字将包中的类隐藏掉
        	import java.sql.{Date=>_, Array=>_,  _}

        -- 7. 使用import关键字将指定类起别名
        	方式一:
        		import java.util.{Date=>UtilDate}
       			new UtilDate()
       	  	方式二:
      		 	type UtilDate = java.util.Date
        		val a : UtilDate = new UtilDate()

        -- 8. Scala默认import是按照包的相对路径进行导入的。
       		a、委派机制 - 没起作用。
        	b、不想使用相对路径,那么可以采用特殊的路径(root)访问,则从最顶层开始查找

       		 println(new _root_.java.util.HashMap())

       -- 9.  import 可以导入对象。
       		a、该对象只能是使用"val"声明的
       		b、样式如下
                val user = new user 
                import user._
                login()
                test()

1.3 类 -class

-- scala中 class 与object在编译时的区别

    --1. 编译时情况:
     	1. object 在编译时会产生两个类文件,一个是当前类的文件, 还有一个是单例的类文件
         	如:User.class, User$.class
  		2. class  在编译时只会产生当前类的class文件
			如:Emp.class
	-- 2. 修饰区别
		1. object:用于修饰伴随着普通的类所产生的一个单例对象,用于模仿java中的静态语法,object中的方法和属性都可以通过类名直接访问,类似于静态语法;
         2. class: 用于修饰普通的类。
       
	-- 3. 汇总:后来我们统一将“相同名称”的class,object声明的类做了区分:
         1.  使用class声明的类:伴生类
         2.  使用object声明的类:伴生对象
         

 -- scala中 class 与 object 在使用上的区别
 
  	--1. 声明的方式:
          1. class: 如果需要通过对象访问属性或方法,那么就使用"class"声明
          2. object: 如果需要通过类名就可以直接访问属性或方法,那么就使用"object"声明

	--2. 构建对象	
          1. class: 需要使用new的方式,由于构造方法无参的原因,小括号可以省略;
          	-- val u = new User()
          	-- val u = new User
          2. object: 可以直接使用类名,但是获取的是"伴生对象",不能使用new
     
    -- 3. 调用方法
  		 1. class: 使用class声明的类无法通过类名直接访问方法或属性,必须构建对象
		 2. object: 使用object声明的类可以通过类名直接访问属性或方法。
  -- 多态声明
       1. Scala中class可以继承(extends)父类
       2. 多态 : 一个对象在不同场合下所表示的不同的状态。
  
  -- 多态使用
       1. Scala当省略类型,编译器会自动将构建对象的类型进行推断。  
       2. 如果需要使用多态操作,那么必须显示声明类型。
  -- java中class 与 scala中class的区别

        --java中
            1. 只能有一个public的类;
            2. public声明的类名需要和文件名称保持一致;
            3. 一个文件可以有多个类;

		-- scala中
			1. 类名与文件名可以不一致;
			2. class可以声明在很多位置;
			3. 一个文件可以有多个公共的类。
  • IDEA中,scala不同类型的文件对应不同的图标

不同的Scala文件

  1. 图标1:表示这个文件中只有伴生对象和伴生类
  2. 图标2:表示这个文件中只有伴生类
  3. 图标3:表示文件内容很复杂
  4. 图标4:表示这个文件中只有伴生对象
  5. 图标5:表示这个文件中是包对

1.4 属性

	-- 属性
	
		--说明
            1. 在类中声明属性就等同于在类中声明局部变量的感觉,可以使用var,val声明;
            2. 可以通过对象在外部访问;
            3. "变量需要显示的初始化"-- 属性的初始化:
            1. 如果想要像java中类的属性初始化一样,需要采用特殊的符号:"下划线"2. 如果属性使用"val"来声明。那么初始值"不能使用下划线",需要显示的赋值;
            3. 使用val声明的属性也不能改。
     
-- 属性 Scala类中声明的属性,不仅仅只有属性,还有其他的内容

	从如下的源码和反编译可知:
	1. 类中声明的属性,都编译为private权限的属性
		a、"val"声明的属性:属性会被直接使用final修饰
   				 private final int age = 10; 
		b、"var"声明的属性:属性只是一个普通的私用变量
				private String name;
				
	2. 使用var声明的属性:"提供属性set和get方法" 
		a、有类似于java中bean对象的get方法,用于返回属性的值
       			public String name() { return this.name }
         b、有类似于java中bean对象的set方法, 用于设定属性的值
                public void name_$eq(String x$1) { this.name = x$1; }
          	
	3. 使用val声明的属性:"只提供属性get方法",不可变的属性
		 a、只有类似于java中bean对象的get方法,用于返回属性的值
				 public int age() { return this.age;  }
   
  	 4. 在使用属性时:
        a、因为属性为私有的,所以给属性赋值,其实等同于调用属性的set方法
      		person.name="zhangsan" --反编译--> person.name_$eq("zhangsan");
        b、因为属性为私有的,所以获取属性值,其实等同于调用属性的get方法 
            val name = person.name  --反编译--> String name = person.name();
  • 源码
object Scala_Variable {
  def main(args: Array[String]): Unit = {

    val person = new Person

  }
  class Person {
    val age = 10
    var name: String = _

  }
}
  • 反编译代码
public final class Scala_Variable{
  public static void main(String[] paramArrayOfString) { 			       Scala_Variable$.MODULE$.main(paramArrayOfString); 
  }
  
  public static class Person
  {
    private String name;
    private final int age = 10; 
      
    public int age() { return this.age;  }
    public String name() { return this.name; } 
    public void name_$eq(String x$1) { this.name = x$1; }
  }
}
 -- scala 与java的bean的结合	
 
	--java Bean规范:
		要求属性的set/get方法起名必须以set,get开头,原因是在框架中,会动态获取属性, 反射调用属性的get方法获取属性值。
    
    --Scala编译生成属性的set,get方法并没有遵循bean规范,这样在很多框架中无法使用。
      	 如果想要scala中的属性符合bean规范,可以采用特殊的注解:"@BeanProperty"
      	 
//源码:
    @BeanProperty
    var name: String = _

//反编译:发现生成满足JavaBean的set和get方法,但方法体内还是调用未加注解前类似java的set和get方法
public String getName() { return name(); } 
public void setName(String x$1) { name_$eq(x$1); }

1.5 权限修饰符(重点)

  • java中的四种权限符
         1.  private    :  私有权限,     "同类"
         2. (default)   :  包权限,      "同类,同包"
         3.  protected  :  受保护权限,  "同类,同包,子类"
         4.  public     :  公共权限,    "任意的地方"
        
      -- 但是你真的了解这四种权限吗?
      1. 声明一个类,那么这个类直接或间接继承于Object类,同时继承object类的方法。
      		object类的方法权限有:public 、 private 、 protected 三种。
      2. 什么是访问权限?
      		权力与限制
      3. 确认是否具有访问权限,屡清楚这两个的关系:
      		a、方法的提供者
      		b、方法的调用者
      4. user.clone(); --> 点不是调用关系,而是从属关系
  • 案例1:
package com.atguigu;
public class java_object {
    public static void main(String[] args) {
        User05 user = new User05();
        user.clone();
    }
}

class User05 {
 private  String name ;
}
/*
深层解析:
1. user.clone(); 是java_object类在main方法中调用了user对象的clone()方法
2.	a、方法的提供者: 因为Usero5未重写Clone()方法,所以该方法来自于父类object,java.lang.Object
    b、方法的调用者:  com.atguigu.java_object
3. clone()权限:protected,所以是同类、同包、子类可以调用
4. com.atguigu.java_object 与 java.lang.Object 不是子父类的关系
*/
"如何理解不是子父类的关系呢?"
 1. 每个类都会将其父类所有的属性和方法加载到自己的类中;
 2. 现在com.atguigu.java_object访问User05中的父类(object),那他们两个就不是父子类的关系。
 3. 是java_object类在main方法中调用了user对象的clone()方法  //这是关键

img

1590429473944
  • scala的权限

        Scala : 4种访问权限

        private        : 私有权限    "同类"
        private[包名]  : 包私有权限,"同类,同包"
        protected      : 受保护权限,"同类,子类"
        (default)      : 公共权限,  "任意的地方", scala中没有public关键字

       --1.  private : 同类
            a、如果属性声明为private,那么编译器生成set,get方法时,也会使用private进行修饰。
            b、使用@BeanProperty注解后,属性不能声明为private
      
       --2.  private[包名] :同类,同包
            a、中括号中的包名可以向上使用
            b、必须在当前包的作用域范围内

       --3. protected : 同类,子类

       --4. (default) : 公共的
        	 Scala中的源码文件中可以声明多个公共类

1.6 方法

	-- 方法: 其实就是类中声明的函数

     1. 默认方法
        a、java.lang.Object的方法
                user.toString
                user.hashCode()
        b、scala中提供的方法
                user.asInstanceOf[User]
                user.isInstanceOf[User]
       		获取对象的类型信息(方法区内存)
        	   val clazz: Class[_ <: User] = user.getClass
       		   val clazz: Class[User] = classOf[User]
 	    c、Predef中的方法

      2. 自定义方法

      -- 方法 - apply(应用)
      
        1. 作用:apply主要作用用于构建对象;
        
        2. 使用场景:当类的构造方法为私有时,使用new"等同于调用对象的构造方法构建对象"的方式就行不通,那么就可以使用apply的方式;
        
        3. 实现原理:一般用于object伴生对象中构建对象,伴生对象可以访问伴生类的"私有"属性和方法;
        
	    4. 细节:
	    	a、Scala会自动识别apply方法,所以调用伴生对象的apply方法时,apply方法名可以省略;
			b、如果不使用new来构建对象,那么等同于调用伴生对象的apply方法;
			c、如果将伴生对象不使用小括号,那么等同于将伴生对象赋值给变量,而不是调用apply方法;
			d、apply方法如果想要被编译器自动识别,那么不能省略小括号;
			e、apply方法主要用于构建对象,但是这个构建对象不一定是当前类的对象;
			f、apply方法可以重载。

	
	-- 方法的重载

        1. 概念: 多个方法名称相同,但是参数列表( 参数个数,参数类型,参数顺序 )不相同的方法之间构成重载
	   
	    2. 应用
            数值类型,在重载的方法中会提升精度。
            引用类型,在重载的方法如果找不到对应的类型。会从类树往上查找

     --  方法的重写x`
        1. 方法的重写一定要存在父子类。
        2. 子类重写父类的方法,子类重写父类相同方法的逻辑
        3. 子类重写方法与父类的方法要求:方法名一致,参数列表保持一致,异常范围"子类抛出的异常不能比父类大",访问权限"子类的访问权限不能比父类低"
        
        如下内容,其实就是虚方法调用的原则,对于"成员方法"来说:"编译看左边,运行看右边,但是对于属性来说,运行和编译都看左边。"
        4. 既然父类和子类有相同的方法,形成了方法的重写。
        5. 那么在调用时,无法确定到底执行哪一个方法,那么需要遵循 动态绑定机制

        6. 动态绑定机制 :程序"执行"过程,如果调用了对象的"成员""方法"时, 会将方法和对象的实际内存进行绑定,然后调用。
        7. 动态绑定机制和属性无关
//方法的重载
package com.atguigu.Scala_chapter01.scala_chapter06_add

/**
  * @Description
  **
  * @author lianzhipeng
  * @create 2020-05-26 0:10:07
  */
object Scala_Method1 {

  def main(args: Array[String]): Unit = {
    val user = test.apply()
    val b : Byte = 10
    user.Method(b)

  }

}
object  test{
  def apply(): test = new test()
}

class test {
//  def Method ( b : Byte) ={
//    println("bbbb")
//  }
  def Method ( b : Char) ={
    println("CCCC")
  }
  def Method ( b : Int) ={
    println("iiii")
  }
//  def Method ( b : Short) ={
//    println("SSSS")
//  }

}


  package com.atguigu;

/**
 * @author lianzhipeng
 * @Description
 * @create 2020-05-26 0:29:52
 */

public class Java_Method {
    public static void main(String[] args) {
        Student student = new Student();
        //情况1:
        System.out.println(student.sum());//40

        //情况2:
        Person student1 = new Student();
        System.out.println(student1.sum());//40

        int i = student1.i;
        System.out.println(i); // 10

        //情况3:注释子类重写的方法,再执行情况2的代码,结果为20
    }
}
class Person {
    int i = 10 ;
    public  int sum(){
        return  i + 10 ;
    }
}
class Student extends  Person {
    int i = 20 ;
//    public  int sum(){
//        return  i + 20 ;
//    }
}

1.7 构造方法

-- 构造方法
       1. 使用new关键字创建的对象其实等同于调用类的构造方法。
       2. Scala是一个完全面向对象的语言。
       3. Scala还是一个完全面向函数的语言。
       4. Scala中类其实也是一个函数,类名其实就是函数名,"类名后面可以增加括号",表示函数参数列表
       5. 这个类名所代表的函数其实就是构造方法,构造函数
       6. 构造方法执行时,会完成类的主体内容的初始化。
       7. 如果在类名的后面增加private关键字,表示主构造方法私有化,无法在外部使用
 -- Scala构造方法只有一个吗?
        --不是。scala中提供了2种不同类型的构造方法
        1. 主构造方法:在类名后加一对小括号的构造方法,可以完成类的初始化
        2. 辅助构造方法:为了完成类初始化的辅助功能而提供的构造方法
                       1.声明方式为:"def this() = {}"
                       2.在使用辅助构造方法时,必须直接或间接地调用主构造方法
                       3.辅助构造方法也存在重载的概念
                       4.辅助构造方法间接调用主构造函数时,"需要保证调用的其他辅助构造函数已经声明过"
package com.atguigu.Scala_chapter01.scala_chapter06_add

/**
  * @Description
  **
  * @author lianzhipeng
  * @create 2020-05-26 1:04:52
  */
object Scala_Construct {
  def main(args: Array[String]): Unit = {

    val person = new Person ("scala")
    
    val person1 = new Person()

    val person2 = new Person("scala",10)
  }

}
class Person (name :String) {

  def this() = {
    this("scala")
  }

  def this (name: String,age:Int) ={
    this()
  }

}

 -- 构造方法之参数

       1. 给构造方法增加参数的目的是什么?
        	从外部将数据传递到对象的属性中
        // java : public User( String name ) { this.username = name }

       2.  Scala中一般构造方法的参数用于属性的初始化,所以为了减少数据的冗余
        	可以使用关键字var,val将构造参数当成类的属性来用。
            "var可读可写,val可读不可写"
       3. 辅助构造方法的参数不能作为属性
package com.atguigu.Scala_chapter01.scala_chapter06_add

/**
  * @Description
  * *
  * @author lianzhipeng
  * @create 2020-05-26 1:04:52
  */
object Scala_Construct {
  def main(args: Array[String]): Unit = {

    //    val person = new Person("scala")

    //    println(person.age)

    //    val person1 = new Person()

    val person2 = new emp("scala", 10)
    println(person2.age) //10

    val emp = new emp()
    println(emp.name) //java
    println(emp.age) //20
    
    val emp1 = new emp("hadoop")
    println(emp1.name) //hadoop
  }

}

class emp(val name: String, var age: Int) {

  def this() = {
    this("java", 20)
  }

  def this(name: String) = {
    this(name, 30)
  }


}

 --   如果父类有构造方法,怎么办? 
        构建子类对象时,应该首先构建父类对象,如果父类的构造方法有参
        那么子类在构建父类对象也应该传递参数。
        
  -- Scala中如何向父类的构造方法中传参?
         在父类名称的后面加括号就可以传参了
package com.atguigu.Scala_chapter01.scala_chapter06_add

/**
  * @Description
  * *
  * @author lianzhipeng
  * @create 2020-05-26 1:04:52
  */
object Scala_Construct {
  def main(args: Array[String]): Unit = {

    val worker  = new Worker("java",30)
    println(worker.age)
    println(worker.str)


  }
}
class Creature ( var name : String ,val age : Int){

}
//方式1
//class  Worker extends  Creature ("java",20){
//
//}

//方式2
class Worker (var str :String , var num :Int) extends  Creature (str , num){

}


1.8 创建对象的方法

-- 方式1: new
-- 方式2: apply
-- 方式3: classof
-- 方式4: clone 【这种方式的类需要实现cloneable接口】
-- 方式5: 反序列化
  • 代码实现
package com.atguigu.Scala_chapter01.scala_review2

/**
  * @Description
  **
  * @author lianzhipeng
  * @create 2020-05-26 18:13:10
  */
object Scala1_CreateObject  extends  Cloneable{
  def main(args: Array[String]): Unit = {

    //创建对象的方法
    //方式1 :new
    val user = new User1
    println(user)

    //方式2 : apply
    val user1 = User1()
    println(user1)

    //方式3 : classof
    val uclass: Class[User1] = classOf[User1]
    val user2: User1 = uclass.newInstance()
    println(user2)

    //方式4 :clone
    val value = clone()
    println(value)

    //方式5 : 反序列化

  }

}
class User1{
  val age = 10

}
object  User1 {
  def apply(): User1 = new User1()
}

1.9 创建单例模式

总结:声明在object中的属性和方法类似java中的静态方法和静态属性,类加载的时候就会被加载。

步骤:
-- java中懒汉式
第一步:私有化构造器
第二步:创建一个私有化的静态属性,并new对象
第三步:创建一个公共的静态方法,返回静态属性

-- scala中
object类中{}的内容只会在初始化的时候加载一次,所以将构建的对象语句放在{}中,并声明为val.

object Scala2_SingObject {
  def main(args: Array[String]): Unit = {
      //调用获取对象的方法,获取两个对象
    val singObject: User2 = User2.singObject
    val singObject1: User2 = User2.singObject
	//判断这两个对象的地址值是否相等
    println(singObject eq singObject1) //true
  }

}
class User2 {
}
object  User2{
    //创建一个单例对象,并设置为不可变的
  val user = new User2
	//创建一个方法,供外部进行调用,返回一个单例对象
  def singObject ={
    user
  }

}

1.10 抽象类

-- 抽象类、抽象方法、抽象属性

 --1. 抽象的理解:抽象的对象一般理解为不完整的对象
        抽象类 : 不完整的类
        抽象方法 :不完整的方法
                  只有声明而没有实现的方法
       			 无需使用abstract关键字修饰
       	抽象属性:不完整的属性,只声明而没有初始化的属性

 --2. 抽象类、抽象方法、抽象属性之间的关系
	   抽象类可以没有抽象方法和抽象属性,有抽象方法或抽象属性的类一定是抽象类
     
 --3. 抽象类的说明
        a、抽象类无法直接构造对象,可通过子类构造对象
        b、抽象类使用"abstract"修饰。
        c、抽象类中可以有完整的方法和完整的属性。
     
 --4. 抽象类与其子类
 		a、子类只有实现抽象类中的所有抽象方法和抽象属性,才能实例化,否则还是抽象类。
 		
 --5. 实现抽象方式的说明
 		a、如果子类重写父类的"完整方法",需要显示增加override关键字来修饰
         b、如果子类重写父类的"抽象方法",需要直接补充完整即可, 或采用override关键字修饰
 
 --6. 实现抽象属性的说明
 		a、子类重写父类的"完整属性",那么需要增加override关键字修饰,"被重写的属性必须是val声明的"
         b、子类重写父类的"抽象属性",那么需要将属性补充完整即可
         
 		关于抽象属性的说明:
 		a、抽象属性在编译时,不会产生类的属性,而是产生属性的set,get方法,并且方法为抽象的。
         b、重写抽象属性,那么等同于普通属性的声明:属性,set,get方法。
 	 
 "问题:为什么子类重写父类完整的属性只能是val,不能是var"
 
 -- 回答:如果采用var声明的属性可以被重写,会产生歧义
解析: 1. Scala中类的属性在编译时,会自动生成私有属性和对应的set,get方法。
      2. 详情见下图分析

1590504029270

1.11 特质

1.11.1java中接口和抽象类说明
-- java中:
       -- 抽象类:将子类共通的内容给抽取出来,放置在父类中
        	a、父类不能直接构建对象,必须通过子类来创建
        	b、抽象类一般在"父子继承""方法重写"的时候用的比较多。
       -- 接口 :和类不一样,不是一个体系,所以可以多继承
      		a、将接口理解为规范和规则。如果一个类符合指定的规则,就应该实现接口
1.11.2 特质基本介绍
    1. Scala中没有接口的概念,也就没有interface关键字。
    2. Scala可以将"多个类中相同的特征"从类里剥离出来,形成特殊的语法结构,称之为“特质”
    3. 如果一个类,符合这个特征,那么就可以将这个特征(特质)混入到类中
1.11.3 特质的使用方式
    1.  使用"trait"声明;
    2.  特质中可以声明抽象方法、抽象属性、以及完整的方法和属性;
    3.  特质既可以看做java中的接口,也可以看做java中的抽象类;
    4.  如果一个类符合特质,那么可以将特质“混入”到类中, 采用extends关键字,如果这个类将抽象部分全部补全,那么可以实例化,否则属于抽象类。
    
    -- 总结:
   	 1. "trait"关键字 可以声明特质
   	 2. 将trait理解为interface :特质之间可以多继承
     3. 将trait理解为抽象类 : 特质也可以继承其他类,也可以被其他类继承,并采用with混入其他的特质
     4. 子类继承特质,如果重写特质中的具体方法,需要使用override
     5. java中所有的接口在Scala中都当成特质来使用        	
// 声明特质
trait Operate {
    // 抽象方法 - 不完整方法
    def oper():Unit
}
class MySQL extends Operate {
    def oper():Unit = {
        println("执行mysql数据操作...")
    }
}
特质的应用:动态扩展功能,遵循 OCP 开发原则
        1. 特质中不仅仅有抽象方法,还可以有具体方法
	    2. 如果对象声明后想要扩展功能,怎么办?
	    3. 特质 (混入with)
object Scala4_trait {
  def main(args: Array[String]): Unit = {

    //构建对象,并使用with “混入”特质2,则拥有特质2所有的属性和方法,如果特质2中也还有抽象方法,那么也需要进行实现
    val user = new User4() with  MySQL
    user.select

  }

}
//特质1:
        trait Operator {
              //抽象方法
              def test () : Unit
        }

//特质2:
        trait  MySQL {
            //完整方法
              def select = {
                println("执行mysql的数据库操作")
              }
        }

//类“混入”特质1,并实现了特质1中的抽象方法
     class User4 extends Operator {
       override def test(): Unit = {
         println("zzzz")
       }
     }
1.11.4 特质的初始化顺序
object Scala5_trait {
  def main(args: Array[String]): Unit = {
    new SubUser35()
    // aaaaa
    // bbbbb
    // ddddd ==> parent class
    // ccccc ==> trait
    // eeeee ==> child class
  }
}
trait Parent35 {
  println("aaaaa")
}
trait Test35 extends Parent35 {
  println("bbbbb")
}
trait SubTest35 extends Parent35 {
  println("ccccc")
}
class User35 extends Test35 {
  println("ddddd")
}
class SubUser35 extends User35 with SubTest35{
  println("eeeee")
}

1590501254061

1.11.5 特质功能执行的顺序
1. 类混入多个特质的时候,功能的执行顺序"从右向左"
2. 特质中的super其实有特殊的含义,表示的"不是父特质,而是上级特质"3. 如果想要改变执行顺序,需要指定特质的类型
object Scala5_trait {
  def main(args: Array[String]): Unit = {
    new MySQL37().operData() //向日志中向数据库中操作数据
  }
}
trait Operate37 {
  def operData(): Unit = {
    println("操作数据")
  }
}
trait DB37 extends Operate37 {
  override def operData(): Unit = {
    print("向数据库中")
    super.operData()
  }
}
trait Log37 extends Operate37 {
  override def operData(): Unit = {
    print("向日志中")
    //super[Operate37].operData()
    super.operData()
  }
}

class MySQL37 extends DB37 with Log37 {

}
1590501563287

1.12 拓展

  • 枚举类
object Scala7_Trait {
  def main(args: Array[String]): Unit = {

    println(User7.RED) //red
    println(User7.YELLOW) //yellow
    println(User7.BLUE) //blue
    println(User7.BLUE.id) //3
    
  }

}

object User7 extends Enumeration {


  val RED = Value(1, "red")
  val YELLOW = Value(2, "yellow")
  val BLUE = Value(3, "blue")
}
  • 应用类
//在没有main方法中,通过继承App特质,使程序也可以执行
//在APP特质中有main方法,因为是继承了app特质,所以当前类则具有了main主方法
object Scala6_app  extends   App {
  println("xxxx")
  println("yyyy")
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值