Scala核心编程_第06章 面向对象编程(基础部分)

摘要:
[修改器将在后面解释]。Scala源文件可以包含多个类//定义一个类Cat//与一个类Cat对应的字节码文件只有一个Cat。类,对应于底部//2的私有名称。两个公共方法name()<}属性/成员变量属性的定义语法:类型]=属性值的定义类型属性:包含值类型或引用类型属性的初始化:

面向对象的Scala

Java是面向对象的编程语言,由于历史原因,Java中还存在着非面向对象的内容:基本类型 ,null,静态方法等。

Scala语言来自于Java,所以天生就是面向对象的语言,而且Scala是纯粹的面向对象的语言,即在Scala中,一切皆为对象。

如何定义类

基本语法

[修饰符] class 类名 {
类体
}

注意:

scala语法中,类并不声明为public,所有这些类都具有公有可见性(即默认就是public),[修饰符在后面再详解].

一个Scala源文件可以包含多个类.

//定义一个类Cat
//一个class Cat 对应的字节码文件只有一个 Cat.class ,默认是public
class Cat {
  //定义/声明三个属性
  //说明
  //1. 当我们声明了 var name :String时, 在底层对应 private name
  //2. 同时会生成 两个public方法 name() <=类似=> getter  public name_$eq() => setter
  var name: String = "" //给初始值
  var age: Int = _ // _ 表示给age 一个默认的值 ,如果Int 默认就是0
  var color: String = _ // _ 给 color 默认值,如果String ,默认是就是""
  def meng(): Unit ={

  }
}

底层逻辑:

public class Cat
{
  private String name = "";
  private int age;
  private String color;

  public String name()
  {
    return this.name; }
  public void name_$eq(String x$1) { this.name = x$1; }
  public int age() { return this.age; }
  public void age_$eq(int x$1) { this.age = x$1; }
  public String color() { return this.color; }
  public void color_$eq(String x$1) { this.color = x$1; }
  public void meng() {}  
}

属性/成员变量

  1. 属性的定义语法:同变量:[访问修饰符] varl 属性名称 [:类型] = 属性值
  2. 属性的定义类型:属性是类的一个组成部分,属性的定义类型可以为任意类型,包含值类型或引用类型
  3. 属性的初始化:
  • Scala中声明一个属性,必须显示的初始化,然后根据初始化数据的类型自动推断,属性类型可以省略(这点和Java不同)。
  • 如果赋值为null,则一定要加类型,因为不加类型, 那么该属性的类型就是Null类型.
  • 如果在定义属性时,暂时不赋值,也可以使用符号_(下划线),让系统分配默认值.

Scala核心编程_第06章 面向对象编程(基础部分)第1张 

class Person {
  var age: Int = 10 //给属性赋初值,省略类型,会自动推导
  var sal = 8090.9
  var Name = null //  是 null类型
  var address1: String = null //ok null=>""
  var address2 = "" //ok 会自动推导=>"" String
}

class A {
  var var1 :String = _  // null
  var var2 :Byte = _  // 0
  var var3 :Double = _  //0.0
  var var4 :Boolean = _  //false
}

 如何创建对象

val | var 对象名 [:类型] = new 类型()
  1. 如果我们不希望改变对象的引用(即:内存地址), 应该声明为val 性质的,否则声明为var, scala设计者推荐使用val ,因为一般来说,在程序中,我们只是改变对象属性的值,而不是改变对象的引用。
  2. scala在声明对象变量时,可以根据创建对象的类型自动推断,所以类型声明可以省略,但当类型和后面new 对象类型有继承关系即多态时,就必须写【:类型】

方法

基本说明

Scala中的方法其实就是函数,声明规则请参考函数式编程中的函数声明。

基本语法

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

方法的调用机制原理

  1. 当我们scala开始执行时,先在栈区开辟一个main栈。main栈是最后被销毁
  2. 当scala程序在执行到一个方法时,总会开一个新的栈。
  3. 每个栈是独立的空间,变量(基本数据类型)是独立的,相互不影响(引用类型除外)
  4. 当方法执行完毕后,该方法开辟的栈就会被jvm机回收。

构造器

基本介绍

构造器(constructor)又叫构造方法,是类的一种特殊的方法,它的主要作用是完成对新对象的初始化。

Scala构造器的介绍

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

Scala构造器的基本语法

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

Scala构造器注

  1. Scala构造器作用是完成对新对象的初始化,构造器没有返回值。
  2. 主构造器的声明直接放置于类名之后
  3. 主构造器会执行类定义中的所有语句,即:构造器也是方法(函数),传递参数和使用方法和前面的函数部分内容没有区别
  4. 如果主构造器无参数,小括号可省略,构建对象时调用的构造方法的小括号也可以省略
  5. 辅助构造器名称为this(这个和Java是不一样的),多个辅助构造器通过不同参数列表进行区分,辅助构造器需要在内部直接或者间接调用柱构造器,本质上辅助构造器在底层就是构造器重载。
  6. 如果想让主构造器变成私有的,可以在()之前加上private,这样用户只能通过辅助构造器来构造对象。
  7. 辅助构造器的声明不能和主构造器的声明一致,会发生错误(即构造器名重复)

代码案例:

object CatDemo {
  def main(args: Array[String]): Unit = {
    var cat=new Cat("wqbin",10)

//    print(cat.name,cat.age) //报错
    println(cat.cname)
    println(cat.cage)
  }
}

//定义一个类Cat
class Cat(name:String,age:Int) {
  var cname: String =name
  var cage: Int =age
  var csex: String =_
  var chobby: String =_

  def this(name:String,age:Int,sex:String){
    this(name,age)//主构造器或者其他构造器
    this.csex=sex
  }
  def this(name:String,age:Int,sex:String,hobby:String){
    this(name,age,sex) //主构造器或者其他构造器
    this.chobby=hobby
  }
}

底层逻辑:

public class Cat
{
  private String cname;
  private int cage;
  private String csex;
  private String chobby;
  
  public Cat(String name, int age)
  {
    this.cname = name;
    this.cage = age;
  }
  
  public Cat(String name, int age, String sex)
  {
    this(name, age);
    csex_$eq(sex);
  }
  
  public Cat(String name, int age, String sex, String hobby)
  {
    this(name, age, sex);
    chobby_$eq(hobby);
  }
  
  public String cname()
  {
    return this.cname;
  }
  
  public void cname_$eq(String x$1)
  {
    this.cname = x$1;
  }
  
  public int cage()
  {
    return this.cage;
  }
  
  public void cage_$eq(int x$1)
  {
    this.cage = x$1;
  }
 
  public String csex()
  {
    return this.csex;
  }
  
  public void csex_$eq(String x$1)
  {
    this.csex = x$1;
  }
  
  public String chobby()
  {
    return this.chobby;
  }
  
  public void chobby_$eq(String x$1)
  {
    this.chobby = x$1;
  }
  
}

私有主构造器,或者辅助构造器:

Scala核心编程_第06章 面向对象编程(基础部分)第2张

构造器参数

  • Scala类的主构造器的形参未用任何修饰符修饰,那么这个参数是局部变量。
  • 如果参数使用val关键字声明,那么Scala会将参数作为类的私有的只读属性使用 。
  • 如果参数使用var关键字声明,那么那么Scala会将参数作为类的成员属性使用,并会提供属性对应的xxx()[类似getter]/xxx_$eq()[类似setter]方法,即这时的成员属性是私有的,但是可读写。
//1. 如果 主构造器是Worker1(inName: String)
// inName就是一个局部变量
class Worker1(inName: String) {
        var name: String = inName
        }
//. 如果 主构造器是Worker2(val inName: String)
// inName就是Worker2的一个private的只读属性
class Worker2(val inName: String) {
        var name: String = inName
        }

// 如果 主构造器是Worker3(var inName: String)
// inName就是Worker3的一个private 的可以读写属性
class Worker3(var inName: String) {
        var name: String = inName
        }

Scala核心编程_第06章 面向对象编程(基础部分)第3张

继承主构造器带参的父类

父类

class China(var name){}

子类

class Japan extends China(name="son"){} 

注意: 我们查看Scala文件编译后的class文件,然后再通过反编译为Java文件可以看到以下代码: 在Japan的默认构造中调用了父类的带参数的构造方法。

public Japan(){super("son");}

如果我们想在Japan中定义和父类相同的属性(覆盖override)则需要注意父类 属性的参数的修饰符必须为val (var 也不行), 否者会报错,在Scala中属性覆盖针对不易变的属性,子类必须加上 override val XXX: Tpye

修改父类:

class China(val name: String){}

修改子类:

class Japan(override val name: String) extends China(name="XX") 

这里父类上的参数必须加上,否者编译不通,如果不想赋值则可以:Chian(name) 直接这样也可以。

以上为原理在开发时不注意这些的话,可以直接简写:

class Japan( name: String ) extends China(name) {}

把 override val 去掉, 变量前面 不要加任何的 权限修饰符。应为Scala的构造方法 是与class写在一起的

看成java的话:

public Japan( name: String ){super.(name)}

总:

Scala的语言设计的初衷就是少写代码,如果父类中有了非val的属性,我们的子类直接就可以在创建对象的时候,默认的构造中可以传入对应的属性值,并且使用该对象也可以访问的到,所以针对于非val的属性没必要override,而val修饰符在编译后的JAVA文件中是final修饰 是最终变量不可变,所以该值在子类中想引用这个变量并且想改变他的值,则需要override val,想想Scala这样设计也是挺合理的

对象创建的流程分析

对象创建的流程分析
看一个案例
class Person {
  var age: Short = 90
  var name: String = _
  def this(n: String, a: Int) {
    this()
    this.name = n
    this.age = a
  }
}
var p : Person = new Person("小倩",20)

1.加载类的信息(属性信息,方法信息)
2.在内存中(堆)开辟空间
4.使用父类的构造器(主和辅助)进行初始
5.使用主构造器对属性进行初始化  
6.使用辅助构造器对属性进行初始化  
7.将开辟的对象的地址赋给 p这个引用

Bean属性

JavaBeans规范定义了Java的属性是像getXxx()和setXxx()的方法。许多Java工具(框架)都依赖这个命名习惯。

为了Java的互操作性。将Scala字段加@BeanProperty时,这样会自动生成规范的 setXxx/getXxx 方法。这时可以使用 对象.setXxx() 和 对象.getXxx() 来调用属性。

注意:给某个属性加入@BeanPropetry注解后,会生成getXXX和setXXX的方法并且对原来底层自动生成类似xxx(),xxx_$eq()方法,没有冲突,二者可以共存。

class Worker1(inName: String) {
        @BeanProperty var name: String = inName
        }

 Scala核心编程_第06章 面向对象编程(基础部分)第4张

  • @beanGetter
  • @beanSetter

免责声明:文章转载自《Scala核心编程_第06章 面向对象编程(基础部分)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇.net mvc使用FlexPaper插件实现在线预览PDF,EXCEL,WORD的方法2.1 顺序栈下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Groovy 学习手册(2)

二. 工具 1. 控制台 groovyConsole: Groovy 控制台是一个非常易于使用和简单的轻量级的编辑器。你可以在里面做很多事情。 在编辑器里面可以书写代码,Windows 下,按下Ctrl + R 来运行代码,清除工作台的输出信息使用Ctrl + W 快捷键。 2. 编译 groovyc: 可以借助 Java 7 的动态调用设计的优势,可...

Jquery 父、子、兄弟节点查询方法

JQUERY的父,子,兄弟节点查找方法: jQuery.parent(expr)  找父亲节点,可以传入expr进行过滤,比如$("span").parent()或者$("span").parent(".class"); jQuery.parents(expr),类似于jQuery.parents(expr),但是是查找所有祖先元素,不限于父元素; jQu...

js之Function原型

在ECMAScript中,Function(函数)类型实际上是对象。每个函数都是Function类型的实例,而且都与其他引用类型一样具有属性和方法。由于函数是对象,因此函数名实际上也是一个指向函数对象的指针。 1、三种函数声明的方式  1》第一种:普通方式声明函数 1 function box (num1,num2){ 2 return nu...

Winform里面的缓存使用

缓存在很多情况下需要用到,合理利用缓存可以一方面可以提高程序的响应速度,同时可以减少对特定资源访问的压力。本文主要针对自己在Winform方面的缓存使用做一个引导性的介绍,希望大家能够从中了解一些缓存的使用场景和使用方法。缓存是一个中大型系统所必须考虑的问题。为了避免每次请求都去访问后台的资源(例如数据库),我们一般会考虑将一些更新不是很频繁的,可以重用的...

Chord算法实现具体

背景 Chord算法是DHT(Distributed Hash Table)的一种经典实现。下面从网上无节操盗了一段介绍性文字: Chord是最简单。最精确的环形P2P模型。“Chord”这个单词在英文中是指“弦”,在分布式系统中指“带弦环”,在P2P领域则指基于带弦环拓扑结构的分布式散列表(DHT)或者构建与其上的P2P网络。尽管MIT和UC Ber...

unittest自定义封装与应用

和大家分享一个自己二次封装uniitest的方法,大家可以在评论区多多指教,一起分享学习; 一、unittest基类封装 import osimport unittestfrom common.log_print import Logfrom common.get_config import getconfigfrom common.base_page_i...