Scala学习笔记(二)

Scala学习笔记(二)

  • 一、创建Scala工程
  • 二、创建类和对象
  • 三、定义和访问成员变量
  • 四、使用下划线初始化成员变量
  • 五、定义成员方法
  • 六、访问修饰符
  • 七、类的构造器
    • 1. 主构造器
    • 2. 辅助构造器
  • 八、单例对象(Object)
    • 1. 定义单例对象
    • 2. 在单例对象中定义成员方法
    • 3. 工具类案例
  • 九、main方法
    • 1. 定义main方法
    • 2. 实现App Trait来定义入口
  • 十、伴生对象
    • 1. 定义伴生对象
    • 2. private[this]访问权限
    • 3. apply方法
  • 十一、继承
    • 1. 定义语法
    • 2. 类继承
    • 3. override和super
  • 十二、类型判断
    • 1. isInstanceOf / asInstanceOf
    • 2. getClass和classOf
  • 十三、抽象类
    • 1. 定义
    • 2. 抽象字段和抽象方法
  • 十四、匿名内部类
  • 十五、特质(trait)
    • 1. 定义
    • 2. trait作为接口使用
    • 3. 定义具体的方法
    • 4. 对象混入trait

一、创建Scala工程

Scala学习笔记(二)_第1张图片
Scala学习笔记(二)_第2张图片
Scala学习笔记(二)_第3张图片
Scala学习笔记(二)_第4张图片
Scala学习笔记(二)_第5张图片
Scala学习笔记(二)_第6张图片

二、创建类和对象

scala是支持面向对象的,也有类和对象的概念。我们依然可以基于scala语言来开发面向对象的应用程序。

  • 语法格式
  • 使用class来定义一个类
  • 使用new来创建对象
  • 示例

    创建一个Person类,并创建它的对象

    1. 创建一个scala项目,并创建一个Object
    2. 添加main方法
    3. 创建类和对象
    // 创建一个Person类
    class Person{}
    
    // 在IDEA中创建项目,并创建一个Object(main方法必须放在Object中)
    object ScalaDemo01 {
    	// 添加main方法
    	def main(args: Array[String]): Unit = {
    		// 在main方法中创建Person类对象
    		val p = new Person()
    		println(p)
     	}
     }
    

三、定义和访问成员变量

像Java一样,每一个类会有自己的属性,例如:Person这样一个类,有自己的姓名和年龄。

  • 语法格式

    • 在类中使用var/val来定义成员变量
    • 对象直接使用成员变量名称来访问成员变量
  • 示例

    1. 定义一个Person类,包含一个姓名和年龄字段
    2. 创建一个名为"张三"、年龄为20岁的对象
    3. 打印对象的名字和年龄
  • 参考代码

    // 创建Person类,添加姓名字段和年龄字段,并对字段进行初始化,让scala自动进行类型推断
    class Person {
        // 定义成员变量
        var name = ""
        var age = 0
    }
    
    // 创建一个Object,添加main方法
    object ScalaDemo02 {
        // 在main方法中创建Person类对象,设置成员变量为"aiden"、23
    	def main(args: Array[String]): Unit = {
    	    // 创建Person对象
    	    val person = new Person
    	    person.name = "aiden"
    	    person.age = 23
    	
    	    // 获取变量值
    	    println(person.name)
    	    println(person.age)
    	}
    }
    

tips:

  • 定义变量var,自动拥有setter和getter方法
  • 定义常量val,相当于java中的final修饰的变量,只有getter方法

四、使用下划线初始化成员变量

scala中有一个更简洁的初始化成员变量的方式,可以让代码看起来更加简洁。

  • 语法格式

    • 在定义var类型的成员变量时,可以使用_来初始化成员变量
      • String => null
      • Int => 0
      • Boolean => false
      • Double => 0.0
    • val类型的成员变量,必须要自己手动初始化
  • 示例

    1. 定义一个Person类,包含一个姓名和年龄字段
    2. 创建一个名为"aiden"、年龄为23岁的对象
    3. 打印对象的名字和年龄
    // 创建Person类,添加姓名字段和年龄字段,指定数据类型,使用下划线初始化
    class Person{
        // 使用下划线进行初始化
        var name:String = _
        var age:Int = _
    }
    
    // 创建一个Object,添加main方法
    object ScalaDemo03{
    	//在main方法中创建Person类对象
    	def main(args: Array[String]): Unit = {
    	    val person = new Person
    	    // 设置成员变量为"aiden"、23
    	    person.name = "aiden"
    	    person.age = 23
    	    //打印对象的名字和年龄
    	    println(person.name)
    	    println(person.age)
      }
    }
    

五、定义成员方法

在scala的类中,也是使用def来定义成员方法

  • 示例

    1. 创建一个Person类
    2. 创建一个该类的对象,并调用sayHello方法
    // 创建Person类,定义成员方法
    class Person {
        def sayHello = println("hello")
    }
    	
    // 创建一个Object,添加main方法
    object ScalaDemo04 {
    	def main(args: Array[String]): Unit = {
    	    val person = new Person
    	    person.sayHello
    	}
    }
    

六、访问修饰符

Java中的访问控制,同样适用于scala,可以在成员前面添加private/protected关键字来控制成员的可见性。但在scala中,没有public关键字,任何没有被标为privateprotected的成员都是公共

  • 示例

    • 创建一个Object,添加main方法
    • 创建Person类,定义私有成员变量和成员方法,并设置getter、setter方法
    • 在main方法中创建该类的对象
    • 设置变量的值,并打印
    // 创建Person类,定义私有成员变量和成员方法
    class Person {
        // 定义私有成员变量
        private var name:String = _
        private var age:Int = _
    	
    	//设置getter、setter方法
        def getName() = name
        def setName(name:String) = this.name = name
        def getAge() = age
        def setAge(age:Int) = this.age = age
    
        // 定义私有成员方法
        private def getNameAndAge = {
          name -> age
        }
    }
    	
    // 创建一个Object,添加main方法
    object ScalaDemo05 {
    	// 在main方法中创建该类的对象
    	def main(args: Array[String]): Unit = {
    	    val person = new Person
    	    // 设置变量的值,并打印
    	    person.setName("张三")
    	    person.setAge(10)
    	    println(person.getName())
    	    println(person.getAge())
    	}
    }
    

七、类的构造器

当创建类对象的时候,会自动调用类的构造器,接下来要学习两个自定义构造器。

  • 主构造器
  • 辅助构造器

1. 主构造器

回顾一下Java的构造器,有构造列表和构造代码块

class Person {
    // 成员变量
    private String name;
    private Integer age;

    // Java构造器
    public Person(String name, Integer age) {
        // 初始化成员变量
        this.name = name;
        this.age = age;
    }
}

在scala中,我们可以使用更简洁的语法来实现。

  • 语法格式

    class 类名(var/val 参数名:类型 = 默认值, var/val 参数名:类型 = 默认值){
    // 构造代码块
    }

tips:

  • 主构造器的参数列表是直接定义在类名后面,添加了val/var表示直接通过主构造器定义成员变量
  • 构造器参数列表可以指定默认值
  • 创建实例,调用构造器可以指定字段进行初始化
  • 在类的内部中,除了方法和属性之外,都是主构造器的一部分
  • 示例

    1. 定义一个Person类,通过主构造器参数列表定义姓名和年龄字段,并且设置它们的默认值
    2. 在主构造器中输出"调用主构造器"
    3. 创建"张三"对象(姓名为张三,年龄为20),打印对象的姓名和年龄
    4. 创建"空"对象,不给构造器传入任何的参数,打印对象的姓名和年龄
    5. 创建"man40"对象,不传入姓名参数,指定年龄为40,打印对象的姓名和年龄
    // 定义类的主构造器
    // 指定默认值
    class Person(var name:String = "", var age:Int = 0) {
        println("调用主构造器")
    }
      
    object ScalaDemo06 {
      	def main(args: Array[String]): Unit = {
    	    // 给构造器传入参数
    	    val zhangsan = new Person("张三", 20)
    	    println(zhangsan.name)
    	    println(zhangsan.age)
    	
    	    println("---")
    	
    	    // 不传入任何参数
    	    val empty = new Person
    	    println(empty.name)
    	    println(empty.age)
    	
    	    println("---")
    	
    	    // 指定字段进行初始化
    	    val man40 = new Person(age = 40)
    	    println(man40.name)
    	    println(man40.age)
      	}
    }
    

2. 辅助构造器

在scala中,除了定义主构造器外,还可以根据需要来定义辅助构造器。例如:允许通过多种方式,来创建对象,这时候就可以定义其他更多的构造器。我们把除了主构造器之外的构造器称为辅助构造器

  • 语法格式

    def this(参数名:类型, 参数名:类型) {
    // 第一行需要调用主构造器或者其他构造器
    // 构造器代码
    }

    • 定义辅助构造器与定义方法一样,也使用def关键字来定义
    • 这个方法的名字必须为this
    • 辅助构造器的第一行代码,必须要调用主构造器或者其他辅助构造器
  • 示例

    • 定义一个Customer类,包含一个姓名和地址字段
    • 定义Customer类的主构造器(初始化姓名和地址)
    • 定义Customer类的辅助构造器,该辅助构造器接收一个数组参数,使用数组参数来初始化成员变量
    • 使用Person类的辅助构造器来创建一个"zhangsan"对象
      • 姓名为张三
      • 地址为北京
    • 打印对象的姓名、地址
    class Customer(var name:String = "", var address:String = "") {
        // 定义辅助构造器
        def this(arr:Array[String]) = {
          	// 辅助构造器必须要调用主构造器或者其他辅助构造器
          	this(arr(0), arr(1))
        }
    }
    
    object ScalaDemo07 {
     	def main(args: Array[String]): Unit = {
    	    val zhangsan = new Customer(Array("张三", "北京"))
    	
    	    println(zhangsan.name)
    	    println(zhangsan.address)
      	}
    }
    

八、单例对象(Object)

scala中没有java中的静态成员,我们想要定义类似于java的static变量、static方法,就要使用到scala中的单例对象——object。

1. 定义单例对象

单例对象表示全局仅有一个对象(类似于java中static概念)

  • 定义单例对象和定义类很像,就是把class换成object
  • 在object中定义的成员变量类似于java的静态变量
  • 可以使用object直接引用成员变量
  • 示例

    1. 创建一个Session类
    2. 创建一个SessionFacroty Object,在其中定义静态方法
    3. 再创建一个Object,在其中添加main方法
    4. 在main方法中用三种方法创建该类的对象
    5. 打印对象,观察地址值
    // 创建一个Session类
    class Session {}
    
    // 创建一个SessionFacroty Object,在其中定义静态方法
    object SessionFactory{
    	val session:Session = new Session
    	def getSession:Session = this.session
    }
    
    // 再创建一个Object,在其中添加main方法
    object ScalaDemo06 {
    	// 在main方法中用三种方法创建该类的对象
    	def main(args: Array[String]): Unit = {
    	    //1. 通过new直接获取对象的实例
    	    val s1 = new Session
    	
    	    //2. 通过对象.属性操作
    	    val s2 = SessionFactory.session
    	
    	    //3. 通过对象.方法操作
    	    val s3 = SessionFactory.getSession
    	
    		// 打印对象,观察地址值
    	    println(s1)//地址:@23223dd8
    	    println(s2)//地址:@4ec6a292
    	    println(s3)//地址:@4ec6a292
    	}
    }
    

2. 在单例对象中定义成员方法

在object中定义的成员方法类似于Java的静态方法

  • 示例

    • 设计一个单例对象,定义一个能够打印分割线(15个减号)的方法
    • 在main方法调用该方法,打印分割线
    object ScalaDemo07 {
    	object PrintUtil {
        	// 打印分割线
        	def printSpliter() = {
          	// 字符串乘法,表示返回多少个字符串
         	 println("-" * 10)
        }
    }
    
    def main(args: Array[String]): Unit = {
        PrintUtil.printSpliter()
      	}
    }
    

3. 工具类案例

  • 示例

    • 编写一个DateUtil工具类专门用来格式化日期时间
    • 定义一个方法,用于将日期(Date)转换为年月日字符串,例如:2030-10-05
    object ScalaDemo08 {
      	object DateUtils {
        	// 在object中定义的成员变量,相当于Java中定义一个静态变量
        	// 定义一个SimpleDateFormat日期时间格式化对象
        	val simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm")
        	// 相当于Java中定义一个静态方法
        	def format(date: Date) = simpleDateFormat.format(date)
      }
     	// main是一个静态方法,所以必须要写在object中
     	def main(args: Array[String]): Unit = {
        	println(DateUtils.format(new Date()))
      	}
    }
    

九、main方法

scala和Java一样,如果要运行一个程序,必须有一个main方法。而在Java中main方法是静态的,而在scala中没有静态方法。在scala中,这个main方法必须放在一个单例对象中。

1. 定义main方法

  • 语法格式

    def main(args:Array[String]):Unit = {
    // 方法体
    }

  • 示例

    创建一个单例对象,在该单例对象中打印"hello, scala"

    object SayHello {
    	def main(args:Array[String]) = {
        	println("hello, scala")
     	}
    }
    

2. 实现App Trait来定义入口

创建一个object,继承自App Trait(特质),然后将需要编写在main方法中的代码,写在object的构造方法体内。

  • 语法格式

    object 单例对象名 extends App {
    // 方法体
    }

  • 示例

    通过继承App特质,来实现一个入口。同样输出"hello, scala"

    object SayHello extends App {
    	println("hello, scala")
    }
    

十、伴生对象

一个class和object具有同样的名字。这个object称为伴生对象,这个class称为伴生类

  • 伴生对象必须要和伴生类一样的名字
  • 伴生对象和伴生类在同一个scala源文件中
  • 伴生对象和伴生类可以互相访问private属性

1. 定义伴生对象

  • 示例

    • 编写一个Person类,定义两个成员变量:name、age
    • 将age定义为private变量
    • 定义Person类的伴生对象,并创建Person对象,调用age属性
    class Person {
        val name = "aiden"
        private val age = 23 //age是私有属性
    }
    
    object Person{
        def main(args: Array[String]): Unit = {
            val person = new Person
            person.age // 伴生对象可以访问私有属性
        }
    }
    

2. private[this]访问权限

如果某个成员的权限设置为private[this],表示只能在当前类中访问,连伴生对象也不可以访问。

  • 示例

    • 编写一个Person类,定义两个成员变量:name、age
    • 将age定义为private[this]变量
    • 定义Person类的伴生对象,并创建Person对象,调用age属性
    class Person {
        val name = "aiden"
        private[this] val age = 23 //age是private[this]属性
    }
    
    object Person{
        def main(args: Array[String]): Unit = {
            val person = new Person
            person.age // 报错
        }
    }
    

    上述代码,会编译报错。

3. apply方法

在类的伴生类对象中,定义apply方法,可以完成在创建对象实例的时候,不用new对象,直接调用。

  • 示例
    • 用辅助构造器定义一个Person类
    • 定义一个Person类的伴生类对象,定义apply方法
    • 创建main方法,通过apply方法,获取对象的实例
    class Person(var name:String)
    
    object Person{
    	def apply (name:String):Person = new Person(name)
    }
    
    object ApplyDemo{
    	def main(args:Array[String]):Unit = {
    		val person = Person("Aiden")
    	}
    }
    

十一、继承

scala语言是支持面向对象编程的,因此也可以使用scala来实现继承,通过继承来减少重复代码。在继承之后可以根据自己的需求修改继承过来的东西,重写override

1. 定义语法

  • scala和java一样,使用extends关键字来实现继承
  • 可以在子类中定义父类中没有的字段和方法,或者重写父类的方法
  • 类和单例对象都可以从某个父类继承
  • 语法格式

    class/object 子类 extends 父类 {
    ...
    }

2. 类继承

  • 示例

    • 定义一个Person类,再定义一个Student类,继承自Person
    • 创建一个Student类object实例,调用sayHello方法
    class Person {
        def sayHello = println("hello")
    }
    
    //使用extends关键字进行继承功能的实现
    class Student extends Person{}
    
    object Student{
        def main(args: Array[String]): Unit = {
          	val student = new Student
         	student.sayHello
        }
    }
    

3. override和super

类似于Java语言,我们在子类中使用override需要来重写父类的成员,可以使用super来引用父类

  • 语法用法

    • 子类要覆盖父类中的一个方法,必须要使用override关键字
    • 使用override来重写一个val字段
    • 使用super关键字来访问父类的成员方法
  • 示例

    • 定义一个Person类,再定义一个Student类,继承自Person
    • 在Student中修改gender属性
    • 创建一个Student类object实例,并打印所有属性和方法
    class Person {
        //变量在子类中可以直接修改赋值,所以不需要进行override
        //只有val修饰的常量需要进行override
        var age:Int = _
        var name:String = _
        val gender:String = "male"
      
        def sayHello = println("hello")
    }
    
    //使用extends关键字进行继承功能的实现
    class Student extends Person{
        //使用override关键词重新继承父类的方法或者属性
        override val gender: String = "female"
    
        //super表示在子类中调用父类的方法
        override def sayHello: Unit = super.sayHello
    }
    
    object Student{
        def main(args: Array[String]): Unit = {
          	val student = new Student
         	student.sayHello
         	println(student.name)
            println(student.age)
            println(student.gender)
        }
    }
    

十二、类型判断

有时候,我们设计的程序,要根据变量的类型来执行对应的逻辑。
Scala学习笔记(二)_第7张图片
在scala中,有两种方式来进行类型判断呢?、

  • isInstanceOf
  • getClass/classOf

1. isInstanceOf / asInstanceOf

在Java中,我们可以使用instanceof关键字来判断类型、以及(类型)object来进行类型转换。而在scala中,对象提供了isInstanceOf和asInstanceOf方法。

  • isInstanceOf判断对象是否为指定类的对象
  • asInstanceOf将对象转换为指定类型
  • 语法格式

    // 判断对象是否为指定类型
    val trueOrFalse:Boolean = 对象.isInstanceOf[类型]

    // 将对象转换为指定类型
    val 变量 = 对象.asInstanceOf[类型]

  • 示例

    • 定义一个Person类
    • 定义一个Student类继承自Person类
    • 创建一个Student类对象
    • 判断该对象是否为Student类型,如果是,将其转换为Student类型并打印该对象
    class Person{}
    class Student extends Person{}
    
    object Main {
      	def main(args: Array[String]): Unit = {
       		val s1:Person = new Student
    
        	// 判断s1是否为Student类型
        	if(s1.isInstanceOf[Student]) {
         		// 将s1转换为Student类型
          		val s2 =  s1.asInstanceOf[Student]
          		println(s2)
        	}
      	}
    }
    

2. getClass和classOf

isInstanceOf 只能判断对象是否为指定类以及其子类的对象,而不能精确的判断出,对象就是指定类的对象。如果要求精确地判断出对象就是指定类的对象,那么就只能使用 getClass 和 classOf 。

  • 语法格式

    • p.getClass可以精确获取对象的类型
    • classOf[x]可以精确获取类型
    • 使用==操作符可以直接比较类型
  • 示例

    • 定义一个Person类
    • 定义一个Student类继承自Person类
    • 创建一个Student类对象,并指定它的类型为Person类型
    • 测试使用isInstance判断该对象是否为Person类型
    • 测试使用getClass/classOf判断该对象是否为Person类型
    • 测试使用getClass/classOf判断该对象是否为Student类型
    class Person{}
    class Student extends Person{}
    
    object Student{
      	def main(args: Array[String]) {
        	val p:Person=new Student
        	//判断p是否为Person类的实例
        	println(p.isInstanceOf[Person])//true
    
        	//判断p的类型是否为Person类
        	println(p.getClass == classOf[Person])//false
    
        	//判断p的类型是否为Student类
        	println(p.getClass == classOf[Student])//true
      	}
    }
    

十三、抽象类

和java语言一样,scala中也可以定义抽象类

1. 定义

如果类的某个成员在当前类中的定义是不包含完整的,它就是一个抽象类

  • 不完整定义有两种情况:

    1. 方法没有方法体(抽象方法
    2. 变量没有初始化(抽象字段

定义抽象类和Java一样,在类前面加上abstract关键字

// 定义抽象类
abstract class 抽象类名 {
// 定义抽象字段
val 抽象字段名:类型
// 定义抽象方法
def 方法名(参数:参数类型,参数:参数类型...):返回类型
}

2. 抽象字段和抽象方法

  • 示例
    • 创建抽象类Person,设置抽象字段和抽象方法
    • 创建Student类,继承Person抽象类,重新Person方法
    //抽象类Person
    abstract class Person {
        var age:Int
        var name:String
        val gender:String
        def sayHello 
    }
    
    //继承抽象类,实现抽象方法
    class Student extends Person{
      override var name: String = "aiden"
      override var age: Int = 23
      override val gender: String = "male"
      override def sayHello: Unit = {
        println("hello")
      }
    }
    

十四、匿名内部类

匿名内部类是没有名称的子类,直接用来创建实例对象。Spark的源代码中有大量使用到匿名内部类。

  • 语法格式

    val/var 变量名 = new 类/抽象类 {
    // 重写方法
    }

  • 示例

    1. 创建一个Person抽象类,并添加一个sayHello抽象方法
    2. 添加main方法,通过创建匿名内部类的方式来实现Person
    3. 调用匿名内部类对象的sayHello方法
    abstract class Person {
      	def sayHello:Unit
    }
    
    object Main {
      	def main(args: Array[String]): Unit = {
        	// 直接用new来创建一个匿名内部类对象
        	val p1 = new Person {
          	override def sayHello: Unit = println("我是一个匿名内部类")
        }
        p1.sayHello
      	}
    }
    

十五、特质(trait)

scala中没有java中的接口(interface),替代的概念是——特质

1. 定义

  • 特质是scala中代码复用的基础单元
  • 它可以将方法和字段定义封装起来,然后添加到类中
  • 与类继承不一样的是,类继承要求每个类都只能继承一个超类,而一个类可以添加任意数量的特质。
  • 特质的定义和抽象类的定义很像,但它是使用trait关键字
  • 语法格式

    • 定义特质
      trait 名称 {
      // 抽象字段
      // 抽象方法
      }
    • 继承特质
      class 类 extends 特质1 with 特质2 {
      // 字段实现
      // 方法实现
      }
  • scala不论是类还是特质,都是使用extends关键字

  • 如果要继承多个trait,则使用with关键字

2. trait作为接口使用

  • 示例

    • 定义一个HelloTrait特质,添加sayHello方法
    • 定义一个ByeTrait特质,添加sayBye方法
    • 定义一个Person类,实现HelloTrait和ByeTrait特质
    • 定义一个Person的object,添加main方法
    • 创建Person对象,实现sayHello和sayBye方法
    trait HelloTrait {
      def sayHello: Unit
    }
    
    trait ByeTrait {
      def sayBye: Unit
    }
    
    class Person extends HelloTrait with ByeTrait {
      override def sayHello: Unit = println("Hello")
    
      override def sayBye: Unit = println("Bye")
    }
    
    object Person {
      def main(args: Array[String]): Unit = {
        val person = new Person
        person.sayHello
        person.sayBye
      }
    }
    

3. 定义具体的方法

和类一样,trait中还可以定义具体的方法

  • 示例

    • 定义一个HelloTrait特质,并添加sayHello具体方法
    • 定义一个Person类,实现HelloTrait特质
    • 定义一个Person的object,添加main方法
    • 创建Person对象,实现sayHello
    trait HelloTrait {
      def sayHello: Unit = println("Hello")
    }
    
    class Person extends HelloTrait  {}
    
    object Person {
      def main(args: Array[String]): Unit = {
        val person = new Person
        person.sayHello
      }
    }
    

4. 对象混入trait

scala中可以将trait混入到对象中,就是将trait中定义的方法、字段添加到一个对象中

  • 语法格式

    val/var 对象名 = new 类 with 特质

  • 示例

    • 定义一个HelloTrait特质,添加sayHello具体方法
    • 定义一个ByeTrait特质,添加sayBye具体方法
    • 定义一个Person类
    • 定义一个Person的object,添加main方法
    • 创建Person1对象,实现sayHello方法
    • 创建Person2对象,实现sayBye方法
    trait HelloTrait {
    	def sayHello: Unit = println("hello")
    }
    
    trait ByeTrait {
    	def sayBye: Unit = println("bye")
    }
    
    class Person {}
    
    object Person {
      	def main(args: Array[String]): Unit = {
    	    val person1 = new Person with HelloTrait
    	    val person2 = new Person with ByeTrait
    	    person1.sayHello
    	    person2.sayBye
      }
    }
    

你可能感兴趣的:(Scala,Scala,学习笔记)