Scala入门(六)面向对象

六、Scala从入门到精通一一面对对象编程(初级) 目录6、面向对象编程6.1、类与对象6.1.1、Scala语言是面向对象的6.1.2、快速入门-面向对象的方式解决养猫问题6.1.3、类与对象的区别和联系6.1.4、如何定义类6.1.5、属性6.1.6、属性/成员变量6.1.7、属性的高级部分6.1.8、如何创建对象6.1.9、类和对象的内存分配机制6.2、方法6.2.1、基本说明6.2.2、基本语法6.2.3、方法案例演示6.2.4、方法的调用... 阅读详情

总目录


Scala 的面向对象思想和 Java 的面向对象思想和概念是一致的。
Scala 中语法和 Java 不同,补充了更多的功能。

1.Scala包

1)基本语法

package 包名

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

(1)区分相同名字的类

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

(3)控制访问范围

1.1 包的命名

1)命名规则

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

2)案例

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

3)命名规范

一般是小写字母+小圆点

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

4)案例

com.test.oa.model 
com.test.oa.controller
com.test.bank.order

1.2 包说明(包语句)

1)说明

Scala 有两种包的管理风格,一种方式和 Java 的包管理风格相同,每个源文件一个包(包名和源文件所在路径不要求必须一致),包名用"."进行分隔以表示包的层级关系,如com.test.scala。另一种风格,通过嵌套的风格表示层级关系,如下

package com {
    package test {
        package scala {
        }
    }
}

第二种风格有以下特点:

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

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

2)案例

// 用嵌套风格定义包
package com {

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

    // 在外层包中定义单例对象
    object Outer {
        var out: String = "out"

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

    package test {
        package scala {
            // 内层包中定义单例对象
            object Inner {
                val in: String = "in"
                def main(args: Array[String]): Unit = {
                    println(Outer.out)
                    Outer.out = "outer"
                    println(Outer.out)
                }
            }
        }
    }
}

1.3 包对象

在 Scala 中可以为每个包定义一个同名的包对象,定义在包对象中的成员,作为其对应包下所有 class 和 object

的共享变量,可以被直接访问。但是如果是在其下定义嵌套包,即上一点第二种风格,是访问不到其内的变量和方

法的,除非第一层包名即为所在包的包名,那么内部的对象才能访问到。

1)定义

package object com{
    val shareValue="share"
    def shareMethod()={}
} 

2)说明

(1)若使用 Java 的包管理风格,则包对象一般定义在其对应包下的 package.scala文件中,包对象名与包名保持一致。

(2)如采用嵌套方式管理包,则包对象可与包定义在同一文件中,但是要保证包对象与包声明在同一作用域中。

如果package test内定义一个package test1,然后将package object test改为package object test1,package test1内的对象访问不了package object test1,必须要在同一作用域才能访问;如果按照以下代码块方式定义,然

后再在package test内定义一个package test1,package test1内对象可以访问package object test。

package test {
    object Outer {
        val out: String = "out"
        def main(args: Array[String]): Unit = {
            println(name)
        }
    }
}

package object test {
    val name: String = "test"
}

1.4 导包说明

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 =>_,_}(ArrayList =>_表示屏蔽掉ArrayList,以逗号为分隔_表

示导入所有的类,出屏蔽类以外)

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

package java {
    package util {
        class HashMap {
        }
    }
}

案例如下:

import com.test.Fruit // 引入 com.test 包下 Fruit(class 和 object)
import com.test._ // 引入 com.test 下的所有成员
import com.test.Fruit._ // 引入 Fruit(object)的所有成员
import com.test.{Fruit,Vegetable} // 引入 com.test 下的 Fruit 和 Vegetable
import com.test.{Fruit=>Shuiguo} // 引入 com.test 包下的 Fruit 并更名为 Shuiguo
import com.test.{Fruit=>Shuiguo,_} // 引入 com.test 包下的所有成员,并将 Fruit 更名为 Shuiguo
import com.test.{Fruit=>_,_} // 引入 com.test 包下屏蔽 Fruit 类
new _root_.java.util.HashMap // 引入的 Java 的绝对路径

2)注意

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

import java.lang._

import scala._

import scala.Predef._

2.类和对象

类:可以看成一个模板

对象:表示具体的事物

2.1 定义类

1)回顾:Java 中的类

如果类是 public 的,则必须和文件名一致。

一般,一个.java 有一个 public 类

注意:Scala 中没有 public,一个.scala 中可以写多个类。

2)基本语法

[修饰符] class 类名 {

类体

}

说明

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

性,可以声明为private,使外部不能访问,但不能是public。

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

3)案例

//(1)Scala 语法中,类并不声明为 public,所有这些类都具有公有可见性(即默认就是 public)
class Person {
}
//(2)一个 Scala 源文件可以包含多个类
class Teacher{
}

2.2 属性

属性是类的一个组成部分

1)基本语法

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

注:Bean 属性(@BeanPropetry),可以自动生成规范的 setXxx/getXxx 方法(类似于Java的@Data)

2)案例

class Test {
    private val t1 = 1
    @BeanProperty
    var t2 = ""
}

object Test {
    def main(args: Array[String]): Unit = {
        val test1 = new Test()
        println(test1.t1)	// 内部,可以直接访问
        // get/set方法
        test.setT2("t2")
        println(test.getT2)
    }
}

object Test1 {
  def main(args: Array[String]): Unit = {
    val test1 = new Test()
    println(test1.t1)	// 会报错,不可访问,若去除private则可以访问
  }
}

注意: 在scala中赋初始值时,可以直接赋下划线,对于引用对象表示空,对于Int表示0,对于Boolean表示false

// 必须要声明为var且此处必须明确指明变量类型
var test1: Int = _

3.封装

封装就是把抽象出的数据和对数据的操作封装在一起,数据被保护在内部,程序的其它部分只有通过被授权的操作

(成员方法),才能对数据进行操作。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 注解实现)。

3.1 访问权限

1)说明

在 Java 中,访问权限分为:public,private,protected 和默认。在 Scala 中,可以通过类似的修饰符达到同样

的效果。但是使用上有区别。

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

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

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

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

class Person {
    private var name: String = "test"
    protected var age: Int = 18
    // 即增加scala_start包的访问权限
    private[scala_start] 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 = {
        // 访问不了name
        println(this.age)
        println(this.sex)
    }
}

3.2 方法

1)基本语法

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

方法体

}

2)案例

class Person {
    private var name: String = "test"
    protected var age: Int = 18
    // 即增加scala_start包的访问权限
    private[scala_start] var sex: String = "男"
    def test(): Unit = {
        println(name)
    }
}

object Person {
    def main(args: Array[String]): Unit = {
        val person = new Person()
        person.test()
    }
}


class Teacher extends Person {
    // 重写需要加override关键字
    override def test(): Unit = {
        println(this.age)
        println(this.sex)
    }
}

3.3 创建对象

1)基本语法

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

2)案例

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

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

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

class Person {
    private var name: String = "test"
    protected var age: Int = 18
    // 即增加scala_start包的访问权限
    private[scala_start] var sex: String = "男"
    def test(): Unit = {
        println(name)
    }
}

object Person {
    def main(args: Array[String]): Unit = {
        // val 修饰对象,不能改变对象的引用(即:内存地址),可以改变对象属性的值。
        val person = new Person()
        person.name = "test"
        //    person = new Person() // 错误的
        var person1 = new Person()
        person1 = new Person()  // 可以改变引用
        println(person.name)
    }
}

3.4 构造器

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

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

1)基本语法

class 类名(形参列表) { // 主构造器
    // 类体
    def this(形参列表) { // 辅助构造器
    }
    
    def this(形参列表) { //辅助构造器可以有多个...
    }
}

说明:

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

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

(3)构造器调用其他另外的构造器,要求被调用构造器必须提前声明。

object Test_Constructor {
  def main(args: Array[String]): Unit = {
    val student1 = new Student1
    student1.Student1()

    val student2 = new Student1("test")
    val student3 = new Student1("test1", 18)
  }
}


// 定义一个类
// 不加括号或者空括号代表主构造器没有参数
class Student1 {
  // 定义属性
  var name: String = _
  var age: Int = _

  println("1. 主构造方法被调用")

  // 声明辅助构造方法
  def this(name: String) {
    // 必须直接或间接的调用主构造器
    this()  // 直接调用主构造器(主构造器空参)
    println("2. 辅助构造方法一被调用")
    this.name = name
    println(s"name: $name age: $age")
  }

  def this(name: String, age: Int) {
    this(name)  // 间接调用主构造器
    println("3. 辅助构造方法二被调用")
    this.age = age
    println(s"name: $name age: $age")
  }

  // 在scala中,可以定义与类名相同的方法,但并非构造方法,而是一个一般方法
  // 此方法默认返回为Unit,代表一个过程
  def Student1(): Unit = {
    println("一般方法被调用")
  }
}

3.5 构造器参数

1)说明

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

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

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

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

2)案例

object Test_ConstructorParams {
    def main(args: Array[String]): Unit = {
        val student2 = new Student2
        println(s"student2: name = ${student2.name} age = ${student2.age}")

        val student3 = new Student3("test", 18)
        println(s"student3: name = ${student3.name} age = ${student3.age}")

        //    访问不到,表示name与age不是Student4的属性,实际上不加修饰的参数只是主构造器的形参
        //    若要实现相应功能,需要在类中实现相应方法
        val student4 = new Student4("test1", 18)
        //    println(s"student4: name = ${student4.name} age = ${student4.age}")
        student4.printInfo()

        val student5 = new Student5("test2", 18)
        println(s"student5: name = ${student5.name} age = ${student5.age}")

        val student6 = new Student6("test3", 18, "test_school")
        student6.printInfo()
    }
}


// 定义类
// 无参构造器
class Student2 {
    // 由于主构造器无参,故属性要单独定义
    // 且如果要创建时初始化属性,那么必须要定义辅助构造器
    var name: String = _
    var age: Int = _
}

// 上述类定义等价于以下形式
// 在此处name与age相当于类的属性
class Student3(var name: String, var age: Int)

// 主构造器参数无修饰
class Student4(name: String, age: Int) {
    def printInfo(): Unit = {
        println(s"student4: name = ${name} age = ${age}")
    }
}

// 使用val修饰,初始化后属性不可再更改
class Student5(val name: String, val age: Int)

class Student6(var name: String, var age: Int) {
    // 可选属性,需要时通过辅助构造器添加
    var school: String = _

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

    def printInfo(): Unit = {
        println(s"student6: name = $name age = $age school = ${school}")
    }
}

4.继承和多态

1)基本语法

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

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

(2)scala 是单继承

2)案例

注意:(1)子类继承父类的属性和方法

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

object Test_Inherit {
    def main(args: Array[String]): Unit = {
        val student1 = new Student7("test", 18)
        val student2 = new Student7("test1", 18, "std001")
    }
}

// 定义一个父类
class Person7 {
    var name: String = _
    var age: Int = _

    println("1. 父类主构造器调用")

    def this(name: String, age: Int) {
        this()
        println("2. 父类的辅助构造器调用")
        this.name = name
        this.age = age
    }

    def printInfo(): Unit = {
        println(s"Person: $name $age")
    }
}

// 定义子类
// extends时实际是调用了父类的主构造器
// 在此处直接extends Person是由于父类主构造器无参
// 若有参,应该extends Person(参数列表),例如:若Person主构造器有参数name,则定义如下注释所示
// class Student7(name: String, age: Int) extends Person(name, age),可以添加一下测试理解
// 由此就变为了调用父类的辅助构造器(辅助构造器才有这两个参数)
class Student7(name: String, age: Int) extends Person7 {
    var stdNo: String = _

    println("3. 子类的主构造器被调用")

    def this(name: String, age: Int, stdNo: String) {
        this(name, age)
        println("4. 子类的辅助构造器调用")
        this.stdNo = stdNo
    }

    override def printInfo(): Unit = {
        println(s"Student: $name $age $stdNo")
    }
}

3)动态绑定

Scala 中属性和方法都是动态绑定,而 Java 中只有方法为动态绑定。

案例实操(对比 Java 与 Scala 的重写)

Java

public class TestDynamicBind {
    public static void main(String[] args) {
        Worker worker = new Worker();
        System.out.println(worker.name);
        worker.hello();
        worker.hi();

        System.out.println("---------------------------");

        // 多态
        Person person = new Worker();
        System.out.println(person.name);    // 在Java中,属性是静态绑定,方法是动态绑定
        person.hello(); // 只有在运行时才去判定具体对象示例
        //        person.hi();  // Person类中无此方法
    }
}

class Person {
    String name = "person";

    public void hello() {
        System.out.println("hello person");
    }
}

class Worker extends Person {
    String name = "worker";

    public void hello() {
        System.out.println("hello worker");
    }

    public void hi() {
        System.out.println("hi worker");
    }
}

Scala

object Test_DynamicBind {
    def main(args: Array[String]): Unit = {
        val student: Person8 = new Student8
        // 在scala中,方法和属性全部都是动态绑定的
        println(student.name) // student
        student.hello() // hello student
    }
}

class Person8 {
    val name: String = "person"

    def hello(): Unit = {
        println("hello person")
    }
}

class Student8 extends Person8 {
    // 在scala中,如果明确要重写父类某属性,必须要添加override关键字
    override val name: String = "student"

    override def hello(): Unit = {
        println("hello student")
    }
}

5.抽象类

5.1 抽象属性和抽象方法

1)基本语法

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

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

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

2)继承&重写

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

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

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

(4)子类对抽象属性进行实现,父类抽象属性可以用 var 修饰;

​ 子类对非抽象属性重写,父类非抽象属性只支持 val 类型,而不支持 var(会报错)。

​ 因为 var 修饰的为可变变量,子类继承之后就可以直接使用,没有必要重写

3)案例

object Test_AbstractClass {
    def main(args: Array[String]): Unit = {
        val student = new Student9
        student.test()
        student.test1()
    }
}

// 定义抽象类
abstract class Person9 {
    // 非抽象属性
    val name: String = "person"

    // 抽象属性
    var age: Int

    // 非抽象方法
    def test(): Unit = {
        println("person test")
    }

    // 抽象方法
    def test1(): Unit
}

// 定义具体的实现类
class Student9 extends Person9 {
    // 实现抽象属性和抽象方法 可以不加override
    var age: Int = 18

    def test1(): Unit = {
        println("student test1")
    }

    // 重写非抽象属性和方法
    override val name: String = "student"

    override def test(): Unit = {
        // 可以使用super关键字调用父类的方法
        // super.test()
        println("student test")
    }
}

5.2 匿名子类

1)说明

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

2)案例

object Test_AnnoymousClass {
    def main(args: Array[String]): Unit = {
        // 由于抽象类不能直接创建对象,必须要实现抽象属性和抽象方法,由此即实现了匿名子类
        val person: Person10 = new Person10 {
            override var name: String = "test"

            override def test(): Unit = println("person test")
        }
        println(person.name)
        person.test()
    }
}

// 定义抽象类
abstract class Person10 {
    var name: String
    def test(): Unit
}

6.单例对象(伴生对象)

Scala语言是完全面向对象的语言,所以并没有静态的操作(即在Scala中没有静态的概念)。但是为了能够和Java

语言交互(因为Java中有静态概念),就产生了一种特殊的对象来模拟类对象,该对象为单例对象。若单例对象名

与类名一致,则称该单例对象这个类的伴生对象,这个类的所有“静态”内容都可以放置在它的伴生对象中声

明。

6.1 单例对象语法

1)基本语法

object Person{

val country:String=“China”

}

2)说明

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

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

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

object Test_Object {
    def main(args: Array[String]): Unit = {
        val student = new Student11("test", 18)
        student.printInfo()
    }
}

// 定义类
class Student11(val name: String, val age: Int) {
    def printInfo(): Unit = {
        println(s"student: name = $name, age = $age, school = ${Student11.school}")
    }
}

// 伴生对象
object Student11 {
    // 在伴生对象中定义的属性相当于静态属性
    // 在伴生对象中定义的方法相当于Java中static修饰的方法
    val school: String = "test"
}

6.2 apply方法

1)说明

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

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

(3)apply 方法可以重载。

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

函数式编程的风格。

(5)当使用 new 关键字构建对象时,调用的其实是类的构造方法,当直接使用类名构建对象时,调用的其实时

伴生对象的 apply 方法。

object Test_Object {
    def main(args: Array[String]): Unit = {
        //    val student = new Student11("test", 18)
        //    student.printInfo()

        val student =  Student11.newStudent("test", 18)
        student.printInfo()

        val student1 = Student11.apply("test1", 18)
        student1.printInfo()

        // 在Scala底层对伴生对象的apply方法有一定的简化,即可以直接省略apply而使用名称(参数列表)
        val student2 = Student11("test1", 18)
        student2.printInfo()
    }
}

// 定义类
// 构造器私有化
class Student11 private(val name: String, val age: Int) {
    def printInfo(): Unit = {
        println(s"student: name = $name, age = $age, school = ${Student11.school}")
    }
}

// 伴生对象
object Student11 {
    // 在伴生对象中定义的属性相当于静态属性
    // 在伴生对象中定义的方法相当于Java中static修饰的方法
    val school: String = "test"

    // 定义一个类的对象实例的创建方法
    def newStudent(name: String, age: Int): Student11 = new Student11(name, age)

    def apply(name: String, age: Int): Student11 = new Student11(name, age)
}

单例设计模式实现

object Test_Singleton {
    def main(args: Array[String]): Unit = {
        val student1 = Student12.getInstance()
        student1.printInfo()

        val student2 = Student12.getInstance()
        student2.printInfo()

        // 引用相同,说明是同一个对象
        println(student1)
        println(student2)
    }
}

class Student12 private(val name: String, val age: Int) {
    def printInfo(): Unit = {
        println(s"student: name = $name, age = $age, school = ${Student11.school}")
    }
}

// 单例设计模式1
//object Student12 {
//  private val student: Student12 = new Student12("test", 18)
//
//  def getInstance(): Student12 = student
//}

// 单例设计模式2
object Student12 {
    private var student: Student12 = _

    def getInstance(): Student12 = {
        if(student == null) {
            // 如果没有对象实例,那么就创建一个
            student = new Student12("test", 18)
        }
        student
    }
}

7.特质(Trait)

Scala 语言中,采用特质 trait(特征)来代替接口的概念,也就是说,多个类具有相同的特质(特征)时,就可以

将这个特质(特征)独立出来,采用关键字 trait 声明。Scala 中的 trait 中即可以有抽象属性和方法,也可以有

具体的属性和方法,一个类可以混入(mixin)多个特质。这种感觉类似于 Java 中的抽象类。Scala 引入 trait 特

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

7.1 特质声明

1)基本语法

trait 特质名 {
    trait 主体
}

2)案例

/ 定义一个特质
trait Young {
    // 声明抽象和非抽象的属性
    var age: Int
    val name: String = "young"

    // 声明抽象和非抽象的方法
    def dating(): Unit

    def play(): Unit = {
        println("young people is playing")
    }
}

7.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 后。

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

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

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

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

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

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

3)案例

object Test_Trait {
    def main(args: Array[String]): Unit = {
        val student: Student13 = new Student13
        student.sayHello()
        student.study()
        student.dating()
        student.play()
    }
}

// 定义一个父类
class Person13 {
    val name: String = "person"
    var age: Int = 18
    def sayHello(): Unit = {
        println("hello from: " + name)
    }
}

// 定义一个特质
trait Young {
    // 声明抽象和非抽象的属性
    var age: Int
    val name: String = "young"

    // 声明抽象和非抽象的方法
    def dating(): Unit

    def play(): Unit = {
        println(s"young people $name is playing")
    }
}

class Student13 extends Person13 with Young {
    // 重写冲突属性(Person13与Young都包含,若不重写则会报错)
    override val name: String = "student"

    // 实现抽象方法
    def dating(): Unit = println(s"student $name is dating")

    def study(): Unit = println(s"student $name is studying")

    // 重写父类方法
    override def sayHello(): Unit = {
        println(s"hello from: student $name")
    }
}

动态混入案例

object Test_TraitMixin {
    def main(args: Array[String]): Unit = {
        val student = new Student14
        student.study()
        student.increase()

        student.play()
        student.increase()

        student.dating()
        student.increase()

        println("------------------------")
        // 动态混入
        val studentWithTalent = new Student14 with Talent {
            override def singing(): Unit = println("student is good at singing")

            override def dancing(): Unit = println("student is good at dancing")
        }

        studentWithTalent.sayHello()
        studentWithTalent.play()
        studentWithTalent.dating()
        studentWithTalent.singing()
        studentWithTalent.dancing()
    }
}

trait Talent {
    def singing(): Unit
    def dancing(): Unit
}

// 定义一个特质
trait Knowledge {
    var amount: Int = 0

    def increase(): Unit
}

class Student14 extends Person13 with Young with Knowledge {
    // 重写冲突属性(Person13与Young都包含,若不重写则会报错)
    override val name: String = "student"

    // 实现抽象方法
    def dating(): Unit = println(s"student $name is dating")

    def study(): Unit = println(s"student $name is studying")

    // 重写父类方法
    override def sayHello(): Unit = {
        println(s"hello from: student $name")
    }

    // 实现特质中的抽象方法
    override def increase(): Unit = {
        amount += 1
        println(s"student $name knowledge increased: $amount")
    }
}

7.3 特质叠加

1)说明

由于一个类可以混入(mixin)多个 trait,且 trait 中可以有具体的属性和方法,若混入的特质中具有相同的方法

(方法名,参数列表,返回值均相同),必然会出现继承冲突问题。冲突分为以下两种:

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

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

2)案例

object Test_TraitOverlying {
    def main(args: Array[String]): Unit = {
        val student = new Student15
        // extends Person13 with Talent15 with Knowledge15
        // 三者方法冲突时,会调用后面的特质的方法
        // 三者是平等的,在叠加时,从后往前叠加,故在调用super时,即使有父类也会调用最后一个特质的方法
        student.increase()
    }
}

trait Talent15 {
    def singing(): Unit
    def dancing(): Unit

    def increase(): Unit = {
        println("talent increased")
    }
}

// 定义一个特质
trait Knowledge15 {
    var amount: Int = 0

    def increase(): Unit = {
        println("knowledge increased")
    }
}

class Student15 extends Person13 with Talent15 with Knowledge15 {
    override def singing(): Unit = println("singing")

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

    override def increase(): Unit = {
        super.increase()
    }
}

7.4 特质叠加执行顺序

当一个类混入多个特质的时候,scala 会对所有的特质及其父特质按照一定的顺序进行排序

排序规则如下:

结论:

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

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

案例如下:

object Test_TraitOverlying {
    def main(args: Array[String]): Unit = {
        val student = new Student15
        // extends Person13 with Talent15 with Knowledge15
        // 三者方法冲突时,会调用后面的特质的方法
        // 三者是平等的,在叠加时,从后往前叠加,故在调用super时,即使有父类也会调用最后一个特质的方法
        // 上述情况是在三者无关联的情况下(即不存在共同的父特质等)
        student.increase()

        // 钻石问题特征叠加
        val footBall = new FootBall
        // 由于ColorBall与CategoryBall有共同的父特质,再根据extends CategoryBall with ColorBall的顺序
        // 根据叠加原则,其实FootBall的super指代ColorBall
        // ColorBall的super指代CategoryBall
        // CategoryBall的super指代Ball
        // 故而调用顺序即FootBall、ColorBall、CategoryBall、Ball
        // 故输出为the ball is a + red- + foot- + ball
        println(footBall.describe())  // the ball is a red-foot-ball
    }
}

// 定义球类特质
trait Ball {
    def describe(): String = "ball"
}

// 定义颜色特征
trait ColorBall extends Ball {
    val color: String = "red"
    override def describe(): String = s"$color-${super.describe()}"
}

// 定义种类特征
trait CategoryBall extends Ball {
    var category: String = "foot"

    override def describe(): String = s"$category-${super.describe()}"
}

// 定义一个自定义球的类
class FootBall extends CategoryBall with ColorBall {
    override def describe(): String = s"the ball is a ${super.describe()}"
}

trait Talent15 {
    def singing(): Unit
    def dancing(): Unit

    def increase(): Unit = {
        println("talent increased")
    }
}

// 定义一个特质
trait Knowledge15 {
    var amount: Int = 0

    def increase(): Unit = {
        println("knowledge increased")
    }
}

class Student15 extends Person13 with Talent15 with Knowledge15 {
    override def singing(): Unit = println("singing")

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

    override def increase(): Unit = {
        super.increase()
    }
}

7.5 特质自身类型

1)说明

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

2)案例

object Test_TraitSelfType {
    def main(args: Array[String]): Unit = {
        val user = new RegisterUser("test", "123456")
        user.insert()
    }
}

// 用户类
class User(val name: String, val password: String)

trait UserDao {
    // UserDao需要使用User的一些属性,又不想二者之间存在继承关系
    // 即可指定一个自身类型,就相当于特质内已含有了User
    // 类似于依赖注入
    _: User =>

    // 向数据插入数据
    def insert(): Unit = {
        println(s"insert into db: ${this.name}")
    }
}

// 定义注册用户类
class RegisterUser(name: String, password: String) extends User(name, password) with UserDao

7.6 特质和抽象类的区别

1.优先使用特质。一个类扩展多个特质是很方便的,但却只能扩展一个抽象类。

2.如果需要构造函数参数,使用抽象类。因为抽象类可以定义带参数的构造函数,而特质不行(有无参构造)。

8.拓展

8.1 类型检查和转换

1)说明

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

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

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

2)案例

object Test_Extends {
    def main(args: Array[String]): Unit = {
        // 类型的检测和转换
        val student: Student17 = new Student17("test", 18)
        student.sayHi()
        student.study()

        val person: Person17 = new Student17("test1", 18)
        person.sayHi()

        println(s"student is Student17: ${student.isInstanceOf[Student17]}")
        println(s"student is Person17: ${student.isInstanceOf[Person17]}")
        println(s"person is Person17: ${person.isInstanceOf[Person17]}")
        println(s"person is Student17: ${person.isInstanceOf[Student17]}")

        val person2: Person17 = new Person17("test2", 18)
        println(s"person2 is Student17: ${person2.isInstanceOf[Student17]}")

        // 类型转换
        if(person.isInstanceOf[Student17]) {
            val newStudent = person.asInstanceOf[Student17]
            newStudent.study()
        }

        println(classOf[Student17])
    }
}

class Person17(val name: String, val age: Int) {
    def sayHi(): Unit = {
        println(s"hi from person: $name")
    }
}

class Student17(name: String, age: Int) extends Person17(name, age) {
    override def sayHi(): Unit = {
        println(s"hi from student: $name")
    }

    def study(): Unit = {
        println("student study")
    }
}

8.2 枚举类和应用类

1)说明

枚举类:需要继承 Enumeration

应用类:需要继承 App

2)案例

object Test_Extends_2 {
    def main(args: Array[String]): Unit = {
        // 测试枚举类
        println(WorkDay.MONDAY)
    }
}

// 定义枚举类对象
object WorkDay extends Enumeration {
    val MONDAY = Value(1, "Monday")
    val TuesDay = Value(2, "TuesDay")
}

// 定义应用类对象
// 可以直接运行
object TestApp extends App {
    println("app start")
}

8.3 Type定义新类型

1)说明

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

2)案例

type String_2 = String
val test: String_2 = "test"
Scala【使用篇】04:Scala面向对象 阅读详情

相关推荐

海思方案定制hi3531dv200/SS528 DVR方案解析:从硬件选型到编解码实战应用

海思方案,Hi3518EV100,Hi3518CV100,Hi3515CV100,Hi3516CV100,Hi3516ECV100,Hi3516D,Hi3516A,Hi3519,Hi3520D,Hi3521A,Hi3535,Hi3531,Hi3536,Hi3536C,Hi3536D,Hi3518EV200,Hi3518EV201,Hi3520DV200,Hi3516CV200,Hi3516CV300,Hi3516AV200,Hi3520DV300,Hi3519V101,sd3403,hi3519av200

1585

Scala面向对象

目录1 类1.1 创建类和对象1.2 getter/setter1.3 类的构造器2 单例对象2.1 定义object2.2 伴生对象2.3 apply方法2.4 main方法3 继承(extends)3.1 简单继承3.2 override和super3.3 isInstanceOf和asInstanceOf3.4 getClass和classOf3.5 访问修饰符3.6 调用父类的constructor3.7 抽象类3.7.1 抽象方法3.7.2 抽象字段3.8 匿名内部类4 特质(trait)7.1

赵广陆 958

OpenRA引擎实战:如何从零开始搭建一个经典RTS游戏模组(附资源包)

本文详细介绍了如何利用开源游戏引擎OpenRA从零开始搭建经典RTS游戏模组。内容涵盖开发环境配置、资源管线处理、YAML规则定义、地图编辑与Lua脚本编写等全流程实战指南,并提供了资源包,帮助开发者和爱好者快速创建属于自己的即时战略游戏世界。

silver的专栏 903

Scala入门系列(六):面向对象之object

objectobject相当于class的单个实例,类似于Java中的static,通常在里面放一些静态的field和method。 第一次调用object中的方法时,会执行object的constructor,也就是object内部不在method或者代码块中的所有代码,但是object不能定义接受参数的constructor 注意:object的构造函数只会在第一次被调用时被执行一次,这...

weixin_30279671的博客 172

保姆级教程:用Python脚本一键把选股结果导入通达信自选股(附完整代码)

本文提供了一份详细的Python自动化教程,教你如何将选股结果一键导入通达信自选股。通过解析通达信文件结构、编写Python脚本实现股票代码转换和批量导入,大幅提升量化交易效率。教程包含完整代码示例,特别适合使用通达信(TDX)的投资者和量化交易开发者。

weixin_30915951的博客 358

手把手教你用HiNet实现图像隐藏:可逆神经网络实战指南(附代码)

本文提供了一份基于HiNet框架实现图像隐藏的实战指南。通过详细解析可逆神经网络原理,手把手指导环境搭建、模型构建、损失函数设计及训练流程,并附有完整代码。该方法利用单个可逆网络统一隐藏与恢复过程,结合小波变换提升隐蔽性,为信息隐藏应用提供了高效解决方案。

rgv234567的博客 433

Scala最基础入门教程

Scala的最基础教程,学完以后,能胜任80%的开发场景,基本控制在2~3个小时阅读时间。

lydms的博客 1万+

深入解析 TDA4VM/VH R5F 核中断机制:VIC 与非 VIC 模式下的实战对比与优化

本文深入解析了TI TDA4VM/VH平台中ARMv7-R架构R5F核的两种中断处理机制:VIC模式与非VIC模式。通过对比硬件自动跳转与软件向量表分发的核心流程、实战代码示例及性能差异,为开发者提供了基于实时性、灵活性与调试需求的选择指南和优化建议,帮助构建更稳定的嵌入式系统。

weixin_29159441的博客 98

十分钟带汝入门大数据开发语言Scala

Scala是一门多范式的编程语言,一种类似Java的编程语言 ,设计初衷是实现可伸缩的语言 、并集成面向对象编程和函数式编程的各种特性。目前最主流的大数据开发框架Spark的实现就是通过Scala去实现的。Scala可以与Java互操作。它用scalac这个编译器把源文件编译成Java的class文件(即在JVM上运行的字节码),也可以从Scala中调用所有的Java类库,也同样可以从Java应用程序中调用Scala的代码。Scala 与 Java 的关系Scala是基于Java去实现的,可以理解为是对

我这么骄傲的一个人。 5万+

SNAP实战:哨兵1 SLC数据预处理全流程详解(附避坑指南)

本文详细解析了使用SNAP软件处理哨兵1号SLC数据的完整预处理流程。从轨道精校正、辐射定标到多视与斑点滤波,再到地理编码,文章提供了清晰的操作步骤与核心逻辑,并重点分享了实践中的常见“坑”与解决方案,旨在帮助用户高效、准确地完成SAR数据预处理。

7up55的博客 1027

2025.06.06【Ribo-seq】|riboWaltz:P-site定位与三碱基周期性分析流程

同学们,大家好!今天我们要学习的是riboWaltz——一款专为Ribo-seq(核糖体足迹测序)数据设计的R包,主要用于P-site定位优化和三碱基周期性分析。P-site的准确定位是Ribo-seq下游所有翻译组学分析的基础,riboWaltz为我们提供了系统、可视化、易用的解决方案。P-site定位优化:自动识别不同长度RPF的最佳P-site偏移量。三碱基周期性分析:可视化RPF在CDS、UTR等区域的分布,评估数据质量。多样本/多条件支持:可同时处理多个样本,便于批量分析和对比。

1793

Scala 入门

Scala 入门 1、概述 1.1、为什么学习 Scala 1)Spark—新一代内存级大数据计算框架,是大数据的重要内容。 2)Spark就是使用Scala编写的。因此为了更好的学习Spark, 需要掌握Scala这门语言。 3)Spark的兴起,带动Scala语言的发展! ● Scala一一Java++ ➢Scala基于JVM,和Java完全兼容,同样具有跨平台、可移植性好、方便的垃圾回收等特性 ➢Scala 比Java更加面向对象 ➢Scala 是一门函数式编程语言 ● Scala更适合大数据的处理

weixin_44966780的博客 1951

Codex,Copilot 是什么

GitHub Copilot是什么 **GitHub Copilot** 是一款由 **GitHub** 和 **OpenAI** 合作开发的 **AI 代码辅助工具**,它基于 **OpenAI Codex 技术**,能够根据上下文自动生成代码建议,大幅提升编程效率

ZhangJiqun&191cm&85kg 6797

Scala 从入门到精通

大数据 spark scala 高阶函数 WordCount

桃李不言下自成蹊 3万+

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

Scala高级语法入门 (三) Scala 面向对象编程 多图详解

Scala 的面向对象思想和 Java 的面向对象思想和概念是一致的。 ` Scala 中语法和 Java 不同,补充了更多的功能

春和的博客 590

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

Scala教程之:面向对象的scala

文章目录面向对象的scalaUnified TypesClassesTraits 面向对象的scala 我们知道Scala是一种JVM语言,可以合java无缝衔接,这也就大大的扩展了scala的应用范围,大数据里面有名的spark就是使用scala编写的,那么scala到底有什么奥秘和特性呢?我们一一来揭秘。 首先scala是一门面向对象的编程语言,他的面向对象性主要表现在如下几个方面: Uni...

程序那些事 4765

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

Scala 入门指南

Scala 是一种多范式编程语言,结合了面向对象编程和函数式编程的特性。它运行在 JVM 上,与 Java 完全兼容,并且可以调用 Java 库。// 简单类// 主构造函数// 辅助构造函数this()this(name)// 基本函数// 无参数函数// 默认参数// 命名参数。

weixin_74417835的博客 1596

scala快速入门

1) JDK1.82) Scala环境变量配置Path,能够快速找到scala相关指令3) 测试cmd输入scala即可1.采用var|val关键字声明2.变量名称应该放置在变量类型之前3.var | val 变量名 :变量类型 = 变量值4.如果根据变量值可以推断出变量类型,那么变量类型就可以省略1.java中的方法在scala中就是函数,只不过方法是相对类的概念,函数在作用域内有效,方法受到类的约束2.函数就是功能的封装不属于类的,所以函数名不能重复,没有重载重写概念。

j218255的博客 1483

【编程语言】Scala入门

通过本次学习,我们系统地掌握了 Scala 语言的核心知识,从多范式编程的独特魅力,到开发环境的搭建,再到基础语法、函数式编程、面向对象编程以及丰富的集合与容器操作,最后通过实战案例将所学知识应用于实际问题的解决。Scala 的强类型系统保障了代码的健壮性,函数式编程特性使代码简洁高效,面向对象编程则赋予了代码良好的结构和可维护性 。

大雨淅淅的博客 2189

Scala学习(六)面向对象

文章目录面向对象Scala包类和对象封装继承和多态抽象属性和抽象方法单例对象(伴生对象)特质 面向对象 Scala 的面向对象思想和 Java 的面向对象思想和概念是一致的。 Scala 中语法和 Java 不同,补充了更多的功能。 Scala包 基本语法:package 包名 Scala 包的三大作用(和 Java 一样) 区分相同名字的类 当类很多时,可以很好的管理类 控制访问范围 包的命名: 命名规则:只能包含数字、字母、下划线、小圆点.,但不能用数字开头,也不要使用关键字。 案例实操:

qq_41816516的博客 921

七、Scala从入门到精通一一面向对象编程(中级)

目录7、包7.1、看一个应用场景7.2、回顾-Java包的三大作用7.3、回顾-Java打包命令7.4、快速入门7.5、Scala包的基本介绍7.6、Scala包快速入门7.7、Scala包的特点概述7.8、scala包的命名7.9、Scala会自动引入的常用包7.10、Scala包注意事项和使用细节7.11、包对象7.12、包对象的应用案例7.13、包对象的底层实现机制分析(重点)7.14、包对...

learp 5620

scala基础入门

目录scala 入门scala和java的关系scala环境安装scala idea环境安装scala 关联源码实现scala中object关键字和class关键字scala 变量和数据类型scala变量标识符命令规范字符串输出数据类型类型的转换泛型Unit类型、Null类型和Nothing类型数值和String类型的转换运算符算术运算符关系运算符逻辑运算符赋值运算符位运算符运算符本质流程控制if -- elseswitchforwhile 和 do ... while循环中断==函数式编程== scala

weixin_44142032的博客 1496
上一篇: 解决 ValueError: urls must start with a leading slash
下一篇: Scala入门(七)集合
Silver  Star
Silver Star 新星创作者: 大数据技术领域 新星创作者: 大数据技术领域
博客等级 码龄7年 1万+粉丝 72原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Silver Star

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值