Scala基础(二)

这篇博客详细介绍了Scala的面向对象特性,包括包管理、类、构造器、继承与多态、抽象类、匿名子类、单例对象以及Trait特质。特别强调了Scala中包的嵌套方式、类的构造器参数、单例对象的伴生概念以及 Trait 作为多重继承的实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Scala的面向对象

Scala 的面向对象思想和 Java 的面向对象思想和概念是一致的。

Scala 中语法和 Java 不同,补充了更多的功能。

1.Scala包

        Scala包与Java类似,有两种管理方式。第一种与Java一毛一样。

        但是在Scala中,还有另一种,即通过嵌套的方式。

package com{
    package zc{
        package hadoop{
        
        }
    }
}

按照嵌套的方式:

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

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

        1.1Scala中的包对象

在 Scala 中可以为每个包定义一个同名的包对象,定义在包对象中的成员,作为其对应包下所有 class 和 object 的共享变量,可以被直接访问。类似于class的伴生对象。

package object Chap02 {
  //定义当前包共享的属性和方法
  val commonValue = "zc"
  def commonMethod()={
    println(commonValue+"在学习")
  }
}

        1.2导包

1)和 Java 一样,可以在顶部使用 import 导入,在这个文件中的所有类都可以使用。

2)局部导入:什么时候使用,什么时候导入。在其作用范围内都可以使用

3)通配符导入:import java.util._

4)给类起名:import java.util.{ArrayList=>JL}

5)导入相同包的多个类:import java.util.{HashSet, ArrayList}

6)屏蔽类:import java.util.{ArrayList =>_,_}

7)导入包的绝对路径:new _root_.java.util.HashMap

注意:Scala 中的三个默认导入分别是 import java.lang._ import scala._ import scala.Predef._

2.Scala 类

在Scala中,没有public(即默认就是 public)

其次,一个Scala源文件可以包含多个类

类的属性(封装)都在下面实现:

object Test1BeanClass {
  def main(args: Array[String]): Unit = {
    val student = new Student
    student.setAge(1)
    student.setSex("ada")

    println(student)
  }
}
/* 修饰符默认public*/class Student{

  private var name :String = _
  //使用 _ 就是默认为该类型的空值
  //在Scala中@BeanProperty我们可以直接获取getset方法
  //但是此时使用@ 的话,我们需要其是private ,那么就很离谱 设计来干嘛。。
  //Scala 中的 public 属性,底层实际为 private,并通过 get 方法(obj.field())和 set 方法
  //(obj.field_=(value))对其进行操作。所以 Scala 并不推荐将属性设为 private,再为其设置
  //public 的 get 和 set 方法的做法。但由于很多 Java 框架都利用反射调用 getXXX 和 setXXX 方
  //法,有时候为了和这些框架兼容,也会为 Scala 的属性设置 getXXX 和 setXXX 方法(通过
  //@BeanProperty 注解实现)。
  @BeanProperty
   var age:Int= _
  @BeanProperty
   var sex:String= _
  override def toString = name+"—"+age+"-"+sex
}

定义方法与定义函数类似。

        2.1创建对象

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

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

(3)自动推导变量类型不能多态,所以多态需要显示声明

object ReviewAAA {
  def main(args: Array[String]): Unit = {
    val c = new testClass
    c.name = "a"
    println(c.name)
  }
}
class testClass{
  var name:String =_
}

        2.2构造器与构造器参数

和 Java 一样,Scala 构造对象也需要调用构造方法,并且可以有任意多个构造方法。 Scala 类的构造器包括:主构造器和辅助构造器。

注意:使用辅助构造器时,一定会先使用主构造器。

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

(1)未用任何修饰符修饰,这个参数就是一个局部变量 (下述demo中的ss对象)

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

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

object TestConstructor {
  def main(args: Array[String]): Unit = {
    new ss("aaa",12).printerInfo()
    val aa = new ss("aa", 111)
    //println(s"aa: name:"+aa.name) 错误  拿不到
    val ab = new ss1("ab",111)
    println(ab.name)//可以访问到
      //那么为什么上面的aa访问不到,因为其只是一个形参,没有实际参数。
  }
}

class Stu {
  //用 _替代初始值
  var name: String = _
  var age: Int = _

  println("主构造器被调用1")

  //辅助构造方法
  def this(name: String) {
    this()
    println("辅助构造器调用2")
    this.name = name
  }

  def this(name: String, age: Int) {
    this(name)
    println("辅助构造器调用3")
    this.age = age
  }
}
class ss1(var name:String,var age:Int)

class ss(name: String, age: Int){
  def printerInfo(): Unit ={
    println(s"name:$name-age:$age")
  }
}

        2.3继承和多态

class 子类名 extends 父类名 { 类体 } (1)子类继承父类的属性和方法 (2)scala 是单继承

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

与Java最大的区别在于,Scala中的继承是动态绑定的。即不仅会继承父类的方法,还要继承父类的属性。

//package Chap02
//
//object DTBinding {
下面这一段用java重写  最后输出的结果是不一样的
///*
//scala的结果中  都是teacher - helloteacher
//java中是 person - helloteacher
//说明java的动态绑定是指绑定了方法,但是scala属性和方法都绑定,都算在继承里面、
// */
//
//}
//class Person1 {
//  val name: String = "person"
//  def hello(): Unit = {
//    println("hello person")
//  }
//}
//class Teacher extends Person1 {
//  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: Person1 = 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();
// }
//}
// */

        2.4抽象类


/*
(1)定义抽象类:abstract class Person{} //通过 abstract 关键字标记抽象类
(2)定义抽象属性:val|var name:String //一个属性没有初始化,就是抽象属性
(3)定义抽象方法:def hello():String //只声明而没有实现的方法,就是抽象方法
(1)如果父类为抽象类,那么子类需要将抽象的属性和方法实现,否则子类也需声明
为抽象类
(2)重写非抽象方法需要用 override 修饰,重写抽象方法则可以不加 override。
(3)子类中调用父类的方法使用 super 关键字
(4)子类对抽象属性进行实现,父类抽象属性可以用 var 修饰;
子类对非抽象属性重写,父类非抽象属性只支持 val 类型,而不支持 var。
因为 var 修饰的为可变变量,子类继承之后就可以直接使用,没有必要重写

 */
object AbsClass {

}
abstract class Person {
  val name: String
  def hello(): Unit
}
class Teacher extends Person {
  val name: String = "teacher"
  override def hello(): Unit = {
    println("hello teacher")
  }
}

        2.5匿名子类

与Java基本一致。

        2.6单例对象

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

package Chap02
/*
(1)单例对象采用 object 关键字声明
(2)单例对象对应的类称之为伴生类,伴生对象的名称应该和伴生类名一致。
(3)单例对象中的属性和方法都可以通过伴生对象名(类名)直接调用访问。
    此时为了保护我们的对象实例,我们可以将其置为private,让所有的别的代码
    必须访问我们的伴生对象中的apply方法用来返回对象。
    即与Java中的getInstance一致。
 */
object SingletonScala {
  //此时 school属性是静态的
  var school :String = "zcStudy"
  def apply(ename:String, age:Int):SingletonScala=new SingletonScala(ename,age)
}
class SingletonScala private(var ename:String ,var age:Int){

}
object maintest{
  def main(args: Array[String]): Unit = {
    println(SingletonScala.school)
    //没有创建直接调用,相当于就是这个类的所有“静态”内容都可以放置在它的伴生对象中声明
    val ss = SingletonScala.apply("a", 1)
    println(ss.age +" "+ ss.ename)
    //有了apply之后可以这样

    var sss = SingletonScala("aoisdh",1231)
    println(sss.age +" "+ sss.ename)
  }
}

        扩展单例模式:在Java中实现单例模式有许多种方法。详情见其他文章。

在Scala中则按照我们的需求,将getInstance放到“静态”即伴生对象中。

/*//饿汉式
object singleton {
  private val single = new singleton("a",11)
  def getInstance():singleton = single
}*/
//懒汉式
object singleton{
  private var ss:singleton =_
  def getInstance():singleton ={
    if(ss == null){
      ss = new singleton("a",11)
    }
     ss
  }
}
class singleton private(var ename:String,var age:Int){
  def printInfo(): Unit ={
    println(ename +" "+ age)
  }
}

3.Trait特质

scala中我们使用Trait特质来替代接口的概念。Scala 中的 trait 中即可以有抽象属性和方法,也可以有具体的属性和方法,一个类可以混入(mixin)多个特质。这种感觉类似于 Java 中的抽象类。

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

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

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

package Chap02
/*
此时出现了菱形继承。  归属的顺序   输出的顺序如下
 student -> knowledge -> talent -> Person
 在继承最末端的先出现
 即 student的super是knowledge 。在demo中也予以证明。
 
 同时当我们需要再附加属性时,只需要在创建时在with新的trait即可。
 */
object TestTraitMixin {
  def main(args: Array[String]): Unit = {
    val s = new student001
    s.abcde()
    s.increase()
    s.increase()
    println(s.selfInfo())
    val sbad = new student001 with Bad {
      override def fighting(): Unit = println("I am a badBoy")

      override val name: String = "badguy"
    }
    println(sbad.name)
    sbad.fighting()

  }
}

class Person001{
  val name =" person "
  val age = -1
  def sayHello(): Unit ={
    println("hello"+name)
  }
  def selfInfo():String={
    "Person"
  }
}
object student001{
  def study(): Unit ={
    println("学习")
  }
}
trait Bad{
  def fighting()
  val name = "badBoy"
}
trait Talent extends Person001 {
  def singing()
  def dancing()
  def abcde(): Unit ={
    println("talent-abcde")
  }
  override def selfInfo() : String ={
    "talent"+" "+super.selfInfo()
  }
}
trait Knowledge extends Person001 {
  var amount = 0;
  def increase()
  def abcde(): Unit ={
    println("Knowledge-abcde")
  }
  override def selfInfo() : String ={
    "knowledge"+" "+super.selfInfo()
  }
}

//此时的super,会继承最后拿一个trait,谁在最后跟谁
class student001 extends Person001 with Talent with Knowledge {
  override def singing(): Unit = println("I can singing")

  override def dancing(): Unit = println("I am dancing")

  override def abcde(): Unit = super.abcde()
  override def increase(): Unit = {
    amount += 1
    println(this.name +"-Knowledge"+" "+ amount)
  }

  override def selfInfo(): String = "Student has "+super.selfInfo()
}

        3.1依赖注入)(自身注入)

scala中直接将  _:(类名) =>   写入到我们需要的代码块中,此时我们可以在该代码块中拿到该类的一系列属性。

//实现了依赖注入的功能
object TestZishen {
  def main(args: Array[String]): Unit = {
    val user = new regis("a", "123")
    user.insert()
  }
}
class User(val name:String,val password: String)
trait Dao{
  _:User =>
  def insert(): Unit ={
    println(s"insert into user values(${this.name},${this.password})")
  }
}

class regis( name:String,password: String)extends User(name,password) with Dao

4.扩展

枚举类与Java基本一致。

应用类,即在里面的代码不需要写main方法可以直接执行。

Type定义新类型

object Test {
 def main(args: Array[String]): Unit = {
 
 type S=String   //创建了一个新类型 S  和String一样
 var v:S="abc"
 def test():S="xyz"
 }
}

类型转换

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

obj.asInstanceOf[T]:将 obj 强转成 T 类型

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值