Fork me on GitHub

Scala变量| 流程控制

 

Scala 是 Scalable Language 的简写,是一门多范式(编程的方式)的编程语言
  Scala是一门以java虚拟机(JVM)为目标运行环境并将面向对象和函数式编程的最佳特性结合在一起的静态类型编程语言。
  Scala 是一门多范式 (multi-paradigm) 的编程语言,Scala支持面向对象和函数式编程
  Scala源代码(.scala)会被编译成Java字节码(.class),然后运行于JVM之上,并可以调用现有的Java类库,实现两种语言的无缝对接。
  Scala 单作为一门语言来看, 非常的简洁高效
终端中输入“scala”命令打开scala解释器(REPL--Read-Eval-Print-Loop)
scala命令行窗口,我们称之为REPL,也称之为交互式解释器。

说明
在命令行窗口中输入scala指令代码时,解释器会读取指令代码 并计算对应的值,然后将结果打印出来(P),接着循环等待用户输入指令。 从技术上讲,这里其实并不是一个解释器,而是指令代码被快速的编译成Java字节码并被JVM加载执行。最终将执行结果输出到命令行中

Scala是一门以java虚拟机(JVM)为运行环境

①先编译完scalac Hello.scala
再执行    scala Hello
②边编译边执行 scala Hello.scala //这种方式会有点慢,每次都要进行编译
解释型(效率低)边编译边执行直接 

 

object TestScala {
  // scala程序的入口依然是main方法
  // scala中声明方法或函数,需要使用def关键字
  // scala中声明的方法默认的访问权限就是public,所以可以省略
  // scala是完全面向对象的语言,所以没有静态语法,没有static关键字
  // scala采用Unit对象代替void
  // java是强类型语言,把类的类型写在前边声明;scala可以推断,看重变量、类的名称,它把变量args写前边;
  // scala中用中括号表示泛型
  def main(args: Array[String]): Unit = {
    printf("Hello scala")

  }
}

 static跟类型 对象相关

由于Scala是完全面向对象的语言,所以是,没有静态语法且没有static关键字的,那么如果想要模拟Java中的静态语法操作,该怎么办呢?

反编译,两个.class文件(两个类)是模仿静态语法,在编译之后有静态static

$ 内部类

Hello.class

import scala.reflect.ScalaSignature;

@ScalaSignature(bytes="\006\001\025:Q!\001\002\t\002\025\tQ\001S3mY>T\021aA\001\by\025l\007\017^=?\007\001\001\"AB\004\016\003\t1Q\001\003\002\t\002%\021Q\001S3mY>\034\"a\002\006\021\005-qQ\"\001\007\013\0035\tQa]2bY\006L!a\004\007\003\r\005s\027PU3g\021\025\tr\001\"\001\023\003\031a\024N\\5u}Q\tQ\001C\003\025\017\021\005Q#\001\003nC&tGC\001\f\032!\tYq#\003\002\031\031\t!QK\\5u\021\025Q2\0031\001\034\003\021\t'O]:\021\007-ab$\003\002\036\031\t)\021I\035:bsB\021qD\t\b\003\027\001J!!\t\007\002\rA\023X\rZ3g\023\t\031CE\001\004TiJLgn\032\006\003C1\001")
public final class Hello{
  public static void main(String[] paramArrayOfString){
    Hello$.MODULE$.main(paramArrayOfString);
  }
}
Hello$.MODULE$(它是静态的,没有值); 对象.main,而对象是空,空指针?不会,因为static静态代码块,在加载类时就new(),调用它的
构造方法-(private Hello$() { MODULE$ = this; })--是私有的,(单例模式),给MODULE$ = this即Hello$赋值了不为空,对象.main方法就不为空了;
所以Hello$.class中的main方法就不是静态的了,而是成员方法,在这个方法里printf("Hello World!")
MODULE是scala自带的类;
scala采用特殊的方法模拟静态访问功能
scala编译类的时候会产生2个类文件,一个是原始类文件,还有一个伴生对象类文件(内部类文件)
如果想要实现静态功能,就必须将静态功能放置在object(伴生对象即例子中的Hello$.class)中; object ->静态可以直接. 方法的提供者和方法的调用者
Object的伴生对象模拟的静态,写成class就不是静态的了;

Hello$.class

import scala.Predef$;
public final class Hello${
  public static final  MODULE$;
  static{
    new ();
  }
  public void main(String[] arrs){
    Predef$.MODULE$.printf("Hello World!");
  }
  private Hello$() { 
    MODULE$ = this; 
  }
}

scala采用了一个伴生对象的概念来实现这个功能。就是说Scala在编译某个类时,不仅仅会生成这个类的字节码文件,
同时,还会生成这个类的关联对象的类文件,我们将这个关联对象称之为这个类的伴生对象(伴随类产生的对象)。
而伴生对象在加载时就自动创建了对象,所以为了模拟静态调用效果,可以将方法声明在伴生对象中,
那么这样在调用方法时,直接通过伴生对象就可以直接调用了,就好像静态调用的效果一样。

 对比java中

①父子类,内部类

②权限问题
③Object中方法:  native委托本地化语言去clone复制(内存中的)对象用

④final,finally,finalize的区别?https://www.cnblogs.com/shengyang17/p/10031596.html

Java中方法重写是基于JVM的动态绑定技术--->模板方法设计模式 https://www.cnblogs.com/shengyang17/p/10010418.html

⑥调用一个为空(null)对象的成员属性或成员方法,-->空指针
  static,scala没有静态语法,没有这个关键字
  它是完全面向对象的

⑦java可以声明局部变量而不进行初始化
而scala不可以;
LocalVariableTable 本地栈变量表,压栈时给每一个变量一个局部变量表LocalVariableTable;
没有s变量,没有初始化只是声明了,它根本不会出现了这里边;java要求变量在使用前必须初始化;
scala中认为你写了就会有用;

变量声明基本语法

var | val 变量名 [: 变量类型] = 变量值 #[]表示可加可不加

注意事项

1)声明变量时,类型可以省略(就是叫 类型自动推断功能)如var s = "ABC" 也可以写上类型var s1 : String = "ABC"

2)类型确定后,就不能修改,说明Scala 是强数据类型语言

3)在声明/定义一个变量时,可以使用var 或者 val 来修饰, var 修饰的变量可改变,val 修饰的变量不可改(不是内容不可改变,是引用)

 

4)val修饰的对象属性在编译后,等同于加上final

val name = "kris"
反编译:
  {
    String name = "kris";
  }
============
object TestVar {
  val age = 10
  def main(args: Array[String]): Unit = {
    val name = "kris"
  }
}
反编译码:
private final int age;
  {
    String name = "kris";
  }

5)var 修饰的对象引用可以改变,val 修饰的则不可改变,但对象的状态(值)却是可以改变的。(比如: 自定义对象、数组、集合等等)

  def main(args: Array[String]): Unit = {
    val name = "kris"
    val user = new User  ##在工作中80%的变量的不会变的;
    user = new User //而这样子就会报错,val修饰的它的引用是不可变的,不是指它的内容不可变;改成var修饰就可以了改变了!!
    user.name = "alex"  //val修饰的它的内容改变了;改变对象里边的属性

  }
}
class User{
  var name = "kk"
}


 6)变量声明时,必须有初始值(显示初始化)。 但在java中可不初始化;

 Scala语言输出的三种方式

%d数字 digit    %f %.2f 四舍五入

字符串通过+号连接(类似java)
    println("name=" + name + " age=" + age + " url=" + url)
    
printf用法 (类似C语言)字符串通过 % 传值。(格式化输出)
    printf("Hello %s \n", "World!")
    printf("Hello %s %d %.2f \n", "alex",2, 3.145)

字符串插值打印:通过$引用(类似PHP)
    println(s"name=$name, age=$age, url=$url")
    
println(s"${name.length}") ---> 4 只是用而不做其他操作可去掉{}

数据类型

Scala 与 Java有着相同的数据类型,在Scala中数据类型都是对象,也就是说scala没有java中的原生(基本)类型

Scala数据类型分为两大类 AnyVal(值类型)AnyRef(引用类型), 注意:不管是AnyVal还是AnyRef 都是对象。

用类AnyVal模拟java中基本类型,Nothing都可以代替AnyVal 和AnyRef

相对于java的类型系统,scala要复杂些!也正是这复杂多变的类型系统才让面向对象编程和函数式编程完美的融合在了一起。

     

在scala中,Any类是所有类的超类。Any有两个子类:AnyVal和AnyRef。

对于直接类型的scala封装类,如Int、Double等,AnyVal是它们的基类;对于引用类型,AnyRef是它们的基类。

Any是一个抽象类,它有如下方法:!=()、==()、asInstanceOf()、equals()、hashCode()、isInstanceOf()和toString()。

AnyVal没有更多的方法了。AnyRef则包含了Java的Object类的一些方法,比如notify()、wait()和finalize()。

AnyRef是可以直接当做java的Object来用的。对于Any和AnyVal,只有在编译的时候,scala编译器才会将它们视为Object。换句话说,在编译阶段Any和AnyVal会被类型擦除为Object。

scala数据类型列表:

char16位--代替不了byte short ; char没有复数,只能走int(从上图可看出)

scala底层指令没有byte和short,有int long float doublt

int整数大小21亿

值类型转换

1)值类型隐式转换

当Scala程序在进行赋值或者运算时,精度小的类型自动转换为精度大的数据类型,这个就是自动类型转换(隐式转换 implicit conversion)。
数据类型按精度(容量)大小排序为:                  ANY

  自动类型转换细节说明:
 ① 有多种类型的数据混合运算时,系统首先自动将所有数据转换成容量最大的那种数据类型,然后再进行计算。
 ② 当我们把精度(容量)大 的数据类型赋值给精度(容量)小 的数据类型时,就会报错,反之就会进行自动类型转换。
 ③ (byte, short) 和 char之间不会相互自动转换。
 ④ byte,short,char 他们三者可以计算,在计算时首先转换为int类型。
 ⑤ 自动提升原则: 表达式结果的类型自动提升为 操作数中最大的类型

2)强制类型转换
 自动类型转换的逆过程,将容量大的数据类型转换为容量小的数据类型。使用时要加上强制转函数,但可能造成精度降低或溢出,格外要注意。
 java : int num = (int)2.5
 scala : var num : Int = 2.7.toInt //灵活,scala中通过方法进行强制类型的转换;

 ① 当进行数据的 从 大——>小,就需要使用到强制转换
 ② 强转符号只针对于最近的操作数有效,往往会使用小括号提升优先级
 ③ Char类型可以保存 Int的常量值,但不能保存Int的变量值,需要强转
 ④ Byte和Short类型在进行运算时,当做Int类型处理。

float 4字节 32位为什么比long 64位的还大呢?? long要转为float
float存的是逻辑算法比如:10^2 +...; long存的是整数


标识符

Scala 对各种变量、方法、函数等命名时使用的字符序列称为标识符;

标识符的命名规则: Scala中的标识符声明,基本和Java是一致的,但是细节上会有所变化。 java中标识符可用中文,只要可变成unicode就可以

1) 首字符为字母,后续字符任意字母和数字,美元符号,可后接下划线_
2) 数字不可以开头。
3) 首字符为操作符(比如+ - * / ),后续字符也需跟操作符 ,至少一个
4) 操作符(比如+-*/)不能在标识符中间和最后.
5) 用反引号(飘号)`....`包括的任意字符串,即使是关键字(39个)也可以

6) _可以作为标识符可声明,不可用

包名:尽量采取有意义的包名,简短,有意义
变量名、函数名 、方法名 采用驼峰法。

Scala有39个关键字:

package, import, class, object, trait, extends, with, type, for
private, protected, abstract, sealed, final, implicit, lazy, override
try, catch, finally, throw
if, else, match, case, do, while, for, return, yield
def, val, var
this, super
new
true, false, null

for循环

  // TODO : scala中的循环方式和java不太相同
    // TODO : scala的for循环其实是对范围对象(Range)进行循环
    // TODO : 范围对象可以传递三个参数:start, end, step
    // TODO : 范围对象(Range)是不包含end的
    // TODO : scala中的循环可以使用to(包含end),until(不包含end)关键字

    for (i <- 1 to 3){
      //println(i) //1 2 3
    }
  //println("##################")
    for (j <- 1 until 3){
      //println(j) //1 2
    }
    //println("##################")
    for (i <- Range(2, 10, 2)){
      //println(i) //2 4 6 8
    }
    // 杨辉三角
    // 九层妖塔
    /*
          *
         ***
        *****
     */

    // TODO : Scala可以一个表达式中声明多行语句,为了理解方便,将小括号变成花括号
/*    for (
      i <- Range(1, 18, 2); j = (18-i)/2 ){
      println(" "*j + "*"* i + " "*j)
    }*/
    for {
      i <- Range(1, 18, 2)
      j = (18-i)/2
      jj = (18-i)/2}{
      println(" "*j + "*"* i + " "*jj)
    }

        *        
       ***       
      *****      
     *******     
    *********    
   ***********   
  *************  
 *************** 
*****************
循环增加守卫条件
//可以对循环增加守卫条件,只有当条件成立,才能执行循环体,类似于continue,所以scala中没有continue关键字
    for (i <-1 to 10 if i > 5){
    println(i)
    }
    //scala中的循环有break操作,但是不是以关键字形式出现。以方法调用的形式出现

scala中所有表达式和运算都有返回值;
这里返回值是满足条件的最后一行代码的结果,如果表达式无值或返回Unit,则返回()
scala中没有for 增强for,for循环也有返回值,默认为()空;
有索引 可迭代--增强for

posted @ 2019-04-04 12:50  kris12  阅读(549)  评论(0编辑  收藏  举报
levels of contents