Scala学习之(六)面向对象

目录

系列文章目录

前言

一、Scala包

1、包的命名

2、包的说明

3、包对象

4、导包说明

5、访问权限

二、类和对象

1.定义类

2.属性

3、方法

4、创建对象

5、构造器

6、构造器参数

三、封装

四、继承

五、抽象属性和抽象方法

1、抽象属性和抽象方法

2、匿名字类

六、单例对象

1、单例对象语法

2、apply方法

七、特质

1、特质声明

2、特质基本语法

 3、特质叠加

4、特质叠加执行顺序

5、特质自身类型

八、扩展

1、类型检查和转换

2、枚举类型和应用类

3、Type定义新类型


前言

提示:这里可以添加本文要记录的大概内容:
例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。


提示:以下是本篇文章正文内容,下面案例可供参考


一、Scala包

1)基本语法

package 包名

2)Scala包的三大作用(和Java一样)

(1)区分相同名字的类

(2)当类很多时,可以很好的管理类

(3)控制访问范围

1、包的命名

1)命名规则

只能包含数字、字母、下划线、小圆点.,但不能用数字开头,也不要使用关键字。

2)案例实操

demo.class.exec1  //错误,因为 class 关键字
demo.12a    //错误,数字开头

3)命名规范

一般是小写字母+小圆点

com.公司名.项目名.业务模块名

4)案例实操

com.sohu.bank.order

2、包的说明

1)说明

scala有两种包的管理风格,一种方式和java的包管理风格相同,每个源文件一个包,包名用“.”进行分隔以表示包的层级关系,如com.localhost.scala。另一种风格,通过嵌套的风格表示层级关系,如下

package com{

    package localhost {

       package scala{

       }
    }
}

第二种风格有以下特点:

(1)一个源文件中可以声明多个package

(2)子包中的类可以直接访问父包中的内容,而无需导包

2)案例实操

package com {

  import com.loclhost.Inner //父包访问子包需要导包

  object Outer {
    val out: String = "out"

    def main(args: Array[String]): Unit = {
      println(Inner.in)
    }
  }


  package loclhost{


    object Inner {

      val in: String = "in"


      def main(args: Array[String]): Unit = {

        println(Outer.out) //子包访问父包无需导包

      }
    }
  }
}


package other {

}

3、包对象

package com {


  object Outer {

    val out: String = "out"


    def main(args: Array[String]): Unit = {

      println(name)

    }

  }

}


package object com {

  val name: String = "com"

}

4、导包说明

1)说明

import com.localhost.Fruit

引入com.localhost包下Fruit(class和object)

import com.localhost._

引入com.localhost下的所有成员

import com.localhost.Fruit._

引入Fruit(object)的所有成员

import com.localhost.{Fruit,Vegetable}

引入com.localhost下的FruitVegetable

import com.localhost.{Fruit=>Shuiguo}

引入com.localhost报下的Fruit并更名为Shuiguo

import com.localhost.{Fruit=>Shuiguo,_}

引入com.localhost包下的所有成员,并将Fruit更名为Shuiguo

import com.localhost.{Fruit=>_,_}

引入com.localhost包下除去Fruit的所有成员

2)注意

scala中的三个默认导入分别是

import java.lang._

import scala._

import scala.Predef._

5、访问权限

1)说明

在Java中,访问权限分为:public,private,protected和默认。在Scala中,你可以通过类似的修饰符达到同样的效果。但是使用上有区别。

(1)scala 中属性和方法的默认访问权限为public,但scala中无public关键字。

(2)private为私有权限,只在类的内部和伴生对象中可用。

(3)protected为受保护权限,Scala中受保护权限比Java中更严格,同类、子类可以访问,同包无法访问。

(4)private[包名]增加包访问权限,包名下的其他类也可以使用

2)案例实操

package com.localhost.scala.test

class Person {


  private var name: String = "bobo"

  protected var age: Int = 18

  private[test] var sex: String = "男"


  def say(): Unit = {

    println(name)

  }
}


object Person {

  def main(args: Array[String]): Unit = {

    val person = new Person

    person.say()

    println(person.name)

    println(person.age)

  }
}

class Teacher extends Person {

  def test(): Unit = {

    this.age

    this.sex

  }
}

class Animal {

  def test: Unit = {

    new Person().sex

  }
}


二、类和对象


1.定义类

1)基本语法

[修饰符] class 类名 {

   类体

}

说明

(1)Scala语法中,类并不声明为public,所有这些类都具有公有可见性(即默认就是public)

(2)一个Scala源文件可以包含多个类

2)案例实操

package com.localhost.chapter07


//(1)Scala语法中,类并不声明为public,所有这些类都具有公有可见性(即默认就是public)

class Person {


}


//(2)一个Scala源文件可以包含多个类

class Teacher{



}


2.属性

属性是类的一个组成部分

1)基本语法

[修饰符] var 属性名称 [:类型] = 属性值

Bean属性(@BeanPropetry),可以自动生成规范的setXxx/getXxx方法

2)案例实操

package com.localhost.scala.test

import scala.beans.BeanProperty

class Person {

  var name: String = "bobo" //定义属性

  var age: Int = _ // _表示给属性一个默认值

  //Bean属性(@BeanProperty)

  @BeanProperty var sex: String = "男"

}

object Person {

  def main(args: Array[String]): Unit = {

    var person = new Person()

    println(person.name)

    person.setSex("女")

    println(person.getSex)

  }
}

3、方法

1)基本语法

def 方法名(参数列表) [:返回值类型] = {

       方法体

}

2)案例实操

class Person {


    def sum(n1:Int, n2:Int) : Int = {

        n1 + n2

    }
}

object Person {

    def main(args: Array[String]): Unit = {

        val person = new Person()

        println(person.sum(10, 20))

    }
}

4、创建对象

1)基本语法

val | var 对象名 [:类型]  = new 类型()

2)案例实操

(1)val修饰对象,不能改变对象的引用(即:内存地址),可以改变对象属性的值。

(2)var修饰对象,可以修改对象的引用和修改对象的属性值

class Person {

    var name: String = "canglaoshi"

}


object Person {

    def main(args: Array[String]): Unit = {

        //val修饰对象,不能改变对象的引用(即:内存地址),可以改变对象属性的值。

        val person = new Person()

        person.name = "bobo"

        // person = new Person()// 错误的

        println(person.name)

    }
}

5、构造器

和Java一样,Scala构造对象也需要调用构造方法,并且可以有任意多个构造方法。

Scala类的构造器包括:主构造器和辅助构造器

1)基本语法

class 类名(形参列表) {  // 主构造器

   // 类体

   def  this(形参列表) {  // 辅助构造器

   }

   def  this(形参列表) {  //辅助构造器可以有多个...

   }

}

说明:

1)辅助构造器,函数的名称this,可以有多个,编译器通过参数的个数来区分。

2)辅助构造方法不能直接构建对象,必须直接或者间接调用主构造方法。

2)案例实操

(1)如果主构造器无参数,小括号可省略,构建对象时调用的构造方法的小括号也可以省略。

//(1)如果主构造器无参数,小括号可省略

//class Person (){

class Person {



  var name: String = _



  var age: Int = _



  def this(age: Int) {

    this()

    this.age = age

    println("辅助构造器")

  }



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

    this(age)

    this.name = name

  }



  println("主构造器")

}



object Person {



  def main(args: Array[String]): Unit = {



    val person2 = new Person(18)

  }

}

6、构造器参数

1)说明

Scala类的主构造器函数的形参包括三种类型:未用任何修饰、var修饰、val修饰

(1)未用任何修饰符修饰,这个参数就是一个局部变量

(2)var修饰参数,作为类的成员属性使用,可以修改

(3)val修饰参数,作为类只读属性使用,不能修改

2)案例实操

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

}

object Test {

  def main(args: Array[String]): Unit = {

    var person = new Person("bobo", 18, "男")

    // (1)未用任何修饰符修饰,这个参数就是一个局部变量

    // printf(person.name)

    // (2)var修饰参数,作为类的成员属性使用,可以修改

    person.age = 19

    println(person.age)

    // (3)val修饰参数,作为类的只读属性使用,不能修改

    // person.sex = "女"

    println(person.sex)

  }
}

三、封装

封装就是把抽象出的数据和对数据的操作封装在一起,数据被保护在内部,程序的其它部分只有通过被授权的操作(成员方法),才能对数据进行操作。java封装操作如下,

(1)将属性进行私有化

(2)提供一个公共的set方法,用于对属性赋值

(3)提供一个公共的get方法,用于获取属性的值

scala中的public属性,底层实际为private,并通过get方法(obj.field())和set方法(obj.field_=(value))对其进行操作。所以scala并不推荐将属性设为private,再为其设置public的get和set方法的做法。但由于很多java框架都利用反射调用getXXX和setXXX方法,有时候为了和这些框架兼容,也会为scala的属性设置getXXX和setXXX方法(通过@BeanProperty注解实现)。

四、继承

1)基本语法

class 子类名 extends 父类名  { 类体 }

(1)子类继承父类的属性方法

(2)scala是单继承

2)案例实操

(1)子类继承父类的属性方法

(2)继承的调用顺序:父类构造器->子类构造器

class Person(nameParam: String) {



  var name = nameParam

  var age: Int = _



  def this(nameParam: String, ageParam: Int) {

    this(nameParam)

    this.age = ageParam

    println("父类辅助构造器")

  }



  println("父类主构造器")

}


class Emp(nameParam: String, ageParam: Int) extends Person(nameParam, ageParam) {

  var empNo: Int = _

  def this(nameParam: String, ageParam: Int, empNoParam: Int) {

    this(nameParam, ageParam)

    this.empNo = empNoParam

    println("子类的辅助构造器")

  }

  println("子类主构造器")

}


object Test {

  def main(args: Array[String]): Unit = {

    new Emp("z3", 11,1001)

  }

}

五、抽象属性和抽象方法

1、抽象属性和抽象方法

1)基本语法

       (1)定义抽象类:abstract class Person{} //通过abstract关键字标记抽象类

       (2)定义抽象属性:val|var name:String //一个属性没有初始化,就是抽象属性

       (3)定义抽象方法:def hello():String //只声明而没有实现的方法,就是抽象方法

案例实操

abstract class Person {

 

  val name: String

  def hello(): Unit

}

class Teacher extends Person {

  override val name: String = "teacher"

  override def hello(): Unit = {

    println("hello teacher")

  }

}

2)继承&重写

(1)如果父类为抽象类,那么子类需要将抽象的属性和方法实现,否则子类也需声明为抽象类

(2)重写非抽象方法需要用override修饰,重写抽象方法则可以不加override。

(3)子类中调用夫类的方法使用super关键字

(4)属性重写只支持val类型,而不支持var。

5scala中属性和方法都是动态绑定,而java中只有方法为动态绑定。

案例实操(对比java与scala的重写)

scala

class Person {

  val name: String = "person"

  def hello(): Unit = {

    println("hello person")

  }

}

class Teacher extends Person {

  override val name: String = "teacher"

  override def hello(): Unit = {

    println("hello teacher")

  }

}

object Test {

  def main(args: Array[String]): Unit = {

    val teacher: Teacher = new Teacher()

    println(teacher.name)

    teacher.hello()

    val teacher1:Person = new Teacher

    println(teacher1.name)

    teacher1.hello()

  }

}

java

class Person {

    public String name = "person";

    public void hello() {

        System.out.println("hello person");

    }

}

class Teacher extends Person {


    public String name = "teacher";

    @Override

    public void hello() {

        System.out.println("hello teacher");

    }

}

public class TestDynamic {

    public static void main(String[] args) {

        Teacher teacher = new Teacher();

        Person teacher1 = new Teacher();

        System.out.println(teacher.name);

        teacher.hello();

        System.out.println(teacher1.name);

        teacher1.hello();

    }

}

结果对比

 scala                                                      java

                               

2、匿名字类

1)说明

Java一样,可以通过包含带有定义或重写的代码块的方式创建一个匿名的子类。

2)案例实操

abstract class Person {

  val name: String

  def hello(): Unit

}

object Test {

  def main(args: Array[String]): Unit = {

    val person = new Person {

      override val name: String = "teacher"

      override def hello(): Unit = println("hello teacher")

    }
  }
}

六、单例对象

        Scala语言是完全面向对象的语言,所以并没有静态的操作(即在Scala中没有静态的概念)。但是为了能够和Java语言交互(因为Java中有静态概念),就产生了一种特殊的对象来模拟类对象,该对象为单例对象。若单例对象名与类名一致,则称该单例对象这个类的伴生对象,这个类的所有“静态”内容都可以放置在它的伴生对象中声明。

1、单例对象语法

1)基本语法

object Person{

       val country:String="China"

}

2)说明

(1)单例对象采用object关键字声明

(2)单例对象对应的类称之为伴生类,伴生对象的名称应该和伴生类名一致。

(3)单例对象中的属性和方法都可以通过伴生对象名(类名)直接调用访问。

3)案例实操

//(1)伴生对象采用object关键字声明

object Person {

  var country: String = "China"

}

//(2)伴生对象对应的类称之为伴生类,伴生对象的名称应该和伴生类名一致。

class Person {

  var name: String = "bobo"

}

object Test {

  def main(args: Array[String]): Unit = {

    //(3)伴生对象中的属性和方法都可以通过伴生对象名(类名)直接调用访问。

    println(Person.country)
  }
}

2、apply方法

1)说明

(1)通过伴生对象apply方法,实现不使用new方法创建对象。

(2)如果想让主构造器变成私有的,可以在()之前加上private。

(3)apply方法可以重载。

(4)Scala中obj(arg)的语句实际是在调用该对象的apply方法,即obj.apply(arg)。用以同一面向对象编程和函数式编程的风格。

2)案例实操

object Test {

  def main(args: Array[String]): Unit = {

    //(1)通过伴生对象的apply方法,实现不使用new关键字创建对象。

    val p1 = Person()

    println("p1.name=" + p1.name)



    val p2 = Person("bobo")

    println("p2.name=" + p2.name)

  }

}

//(2)如果想让主构造器变成私有的,可以在()之前加上private

class Person private(cName: String) {

  var name: String = cName

}

object Person {

  def apply(): Person = {

    println("apply空参被调用")

    new Person("xx")

  }

  def apply(name: String): Person = {

    println("apply有参被调用")

    new Person(name)

  }

}

七、特质

Scala语言中,采用特质trait(特征)来代替接口的概念,也就是说,多个类具有相同的特征(特征)时,就可以将这个特质(特征)独立出来,采用关键字trait声明。

Scala中的trait中即可以有抽象属性和方法,也可以有具体的属性和方法一个类可以混入(mixin)多个特质

Scala引入trait特征,第一可以替代Java的接口,第二个也是对单继承机制的一种补充。

1、特质声明

1)基本语法

trait 特质名 {

       trait体

}

2)案例实操

trait PersonTrait {

    // 声明属性

    var name:String = _

    // 声明方法

    def eat():Unit={


    }

    // 抽象属性

    var age:Int

    // 抽象方法

    def say():Unit

}

2、特质基本语法

一个类具有某种特质(特征),就意味着这个类满足了这个特质(特征)的所有要素,所以在使用时,也采用了extends关键字,如果有多个特质或存在父类,那么需要采用with关键字连接。

1)基本语法:

没有父类:class  类名 extends  特质1   with    特质2   with   特质3 …

有父类:class  类名  extends  父类   with  特质1   with   特质2  with 特质3…

2)说明

       (1)类和特质的关系:使用继承的关系。

       (2)当一个类去继承特质时,第一个连接词是extends,后面是with。

       (3)如果一个类在继承特质和父类时,应当把父类写在extends后。

3)案例实操

(1)特质可以同时拥有抽象方法和具体方法

(2)一个类可以混入(mixin)多个特质

(3)所有的Java接口都可以当做Scala特质使用

(4)动态混入:可灵活的扩展类的功能

4.1)动态混入:创建对象时混入trait,而无需使类混入该trait

(4.2)如果混入的trait中有未实现的方法,则需要实现

trait PersonTrait {


  //(1)特质可以同时拥有抽象方法和具体方法

  // 声明属性

  var name: String = _

  // 抽象属性

  var age: Int


  // 声明方法

  def eat(): Unit = {

    println("eat")

  }

  // 抽象方法

  def say(): Unit

}


trait SexTrait {

  var sex: String

}


//(2)一个类可以实现/继承多个特质

//(3)所有的Java接口都可以当做Scala特质使用

class Teacher extends PersonTrait with java.io.Serializable {


  override def say(): Unit = {

    println("say")

  }

  override var age: Int = _

}


object TestTrait {

  def main(args: Array[String]): Unit = {

    val teacher = new Teacher

    teacher.say()

    teacher.eat()


    //(4)动态混入:可灵活的扩展类的功能

    val t2 = new Teacher with SexTrait {

      override var sex: String = "男"

    }


    //调用混入trait的属性

    println(t2.sex)

  }
}

 3、特质叠加

由于一个类可以混入(mixin)多个trait,且trait中可以有具体的属性和方法,若混入的特质中具有相同的方法(方法名,参数列表,返回值均相同),必然会出现继承冲突问题。冲突分为以下两种:

第一种,一个类(Sub)混入的两个trait(TraitA,TraitB)中具有相同的具体方法,且两个trait之间没有任何关系,解决这类冲突问题,直接在类(Sub)中重写冲突方法。

第二种,一个类(Sub)混入的两个trait(TraitA,TraitB)中具有相同的具体方法,且两个trait继承自相同的trait(TraitC),及所谓的“钻石问题”,解决这类冲突问题,Scala采用了特质叠加的策略。

所谓的特质叠加,就是将混入的多个trait中的冲突方法叠加起来,案例如下,

trait Ball {

  def describe(): String = {

    "ball"

  }

}

trait Color extends Ball {

  override def describe(): String = {

    "blue-" + super.describe()

  }

}

trait Category extends Ball {

  override def describe(): String = {

    "foot-" + super.describe()

  }

}


class MyBall extends Category with Color {

  override def describe(): String = {

    "my ball is a " + super.describe()

  }

}

object TestTrait {

  def main(args: Array[String]): Unit = {

    println(new MyBall().describe())

  }

}

结果如下:

4、特质叠加执行顺序

思考:上述案例中的super.describe()调用的是父trait中的方法吗?

当一个类混入多个特质的时候,scala会对所有的特质及其父特质按照一定的顺序进行排序,而此案例中的super.describe()调用的实际上是排好序后的下一个特质中的describe()方法。,排序规则如下:

 结论:

       (1)案例中的super,不是表示其父特质对象,而是表示上述叠加顺序中的下一个特质,即,MyClass中的super指代ColorColor中的super指代CategoryCategory中的super指代Ball

(2)如果想要调用某个指定的混入特质中的方法,可以增加约束:super[],例如super[Category].describe()。

5、特质自身类型

1)说明

       自身类型可实现依赖注入的功能。

2)案例实操

class User(val name: String, val age: Int)

trait Dao {

  def insert(user: User) = {

    println("insert into database :" + user.name)

  }

}

trait APP {

  _: Dao =>

  def login(user: User): Unit = {

    println("login :" + user.name)

    insert(user)

  }

}

object MyApp extends APP with Dao {

  def main(args: Array[String]): Unit = {

    login(new User("bobo", 11))

  }

}

八、扩展

1、类型检查和转换

1)说明

(1)obj.isInstanceOf[T]:判断obj是不是T类型。

(2)obj.asInstanceOf[T]:将obj强转成T类型。

(3)classOf获取对象的类名。

2)案例实操

class Person{

}

object Person {

    def main(args: Array[String]): Unit = {

        val person = new Person

        //(1)判断对象是否为某个类型的实例

        val bool: Boolean = person.isInstanceOf[Person]

        if ( bool ) {

            //(2)将对象转换为某个类型的实例

            val p1: Person = person.asInstanceOf[Person]

            println(p1)

        }

        //(3)获取类的信息

        val pClass: Class[Person] = classOf[Person]

        println(pClass)
    }
}

2、枚举类型和应用类

1)说明

       枚举类:需要继承Enumeration

       应用类:需要继承App

2)案例实操

object Test {
    def main(args: Array[String]): Unit = {

        println(Color.RED)
    }
}

// 枚举类
object Color extends Enumeration {
    val RED = Value(1, "red")
    val YELLOW = Value(2, "yellow")
    val BLUE = Value(3, "blue")
}

// 应用类
object Test20 extends App {
    println("xxxxxxxxxxx");
}

3、Type定义新类型

1)说明

使用type关键字可以定义新的数据数据类型名称,本质上就是类型的一个别名

2)案例实操

object Test {

    def main(args: Array[String]): Unit = {
       
        type S=String
        var v:S="abc"
        def test():S="xyz"
    }
}



 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Scala是一种多范式编程语言,既可以用于面向对象编程,也可以用于函数式编程,支持静态类型检查和类型推断。它受到Java和Ruby的启发,同时也受到函数式编程语言的影响,如Haskell和Erlang。 ### 回答2: Scala主要是学习以下几种语言: 1. Java:Scala是一种在Java虚拟机上运行的编程语言,并且与Java语言高度兼容。因此,学习Scala需要具备一定的Java基础,包括Java的面向对象编程思想、语法和常用的类库。 2. Functional Programming(函数式编程):Scala是一种支持函数式编程的语言,它引入了许多函数式编程的概念和特性,如高阶函数、不可变性和模式匹配等。因此,学习Scala需要学习一些函数式编程的基本理念和技术。 3. Static Typing(静态类型):与Java类似,Scala是一种静态类型语言,需要声明变量的类型,并且在编译时进行类型检查。因此,学习Scala需要对静态类型语言的基本概念和类型系统有一定的了解。 4. Object-Oriented Programming(面向对象编程):Scala是一种面向对象的语言,支持类、继承、多态等面向对象编程的特性。因此,学习Scala需要熟悉面向对象编程的基本思想和常用的设计模式。 总之,学习Scala需要掌握Java的基础知识、函数式编程的概念和技术,以及静态类型和面向对象编程的思想。这些知识将帮助开发者更好地理解和应用Scala编程语言。 ### 回答3: Scala主要是学习Java和函数式编程的语言。 首先,Scala是一种同时支持面向对象编程和函数式编程的语言。在面向对象方面,它借鉴了Java的语法和面向对象思想,因此熟悉Java的人可以很快上手ScalaScala提供了类、继承、多态和接口等特性,使得开发者可以使用面向对象的方式来组织代码和实现复杂的程序。 其次,Scala也是一种函数式编程语言,它引入了很多函数式编程的概念和特性。函数是Scala中的一等公民,可以作为参数或返回值进行传递。Scala提供了很多高阶函数的概念,比如map、filter和reduce等,这些函数可以很方便地操作集合数据。此外,Scala还支持不可变的数据结构和模式匹配等函数式编程的特性。 由于Scala和Java的紧密联系,学习Scala的过程中,对Java的知识会有帮助。熟悉Java的开发者可以借助Scala的优势来提高开发效率和代码可读性。同时,Scala也为Java开发者提供了平滑迁移的途径,可以逐渐引入Scala的特性和概念,使得代码更加简洁和灵活。 综上所述,学习Scala主要是学习Java和函数式编程的语言。掌握Java的开发者可以更快上手Scala,并且通过学习Scala的函数式编程特性,可以拓展自己的编程思维和方式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值