Scala注释-序列化和反射

1. annotations-注解

注解说明
    是插入到代码中以便有工具可以对它们进行处理的标签。
    类型检查的新途径

注解的级别
        工具可以在代码级别运作,也可以处理被编译器加入了注解信息的类文件。
注解的使用的类和语言
    Scala中可以为类、方法、字段、局部变量和参数添加注解,与Java一样。可以同时添加多个注解,先后顺序没有影响
        可以对Scala类使用Java注解。
        也可以使用Scala注解,是由Scala注解特有的,通常由Scala编译器或编译器插件处理。
Java注解和Scala注解的区别
    Java注解并不影响编译器如何将源码翻译成字节码,仅仅往字节码中添加数据,以便外部工具可以利用它们。
    而在Scala中,注解可以影响编译过程,比如 @BeanProperty注解

常用注解说明
        @transient注解将字段标记为瞬态的;
                transient关键字修饰的变量不再能被序列化,一个静态变量不管是否被transient修饰,均不能被序列化
                这个注解一般用于序列化的时候,标识某个字段不用被序列化
        @tailrec注释---尾递归优化

注释处理器   
        使用反射机制的API

类型擦除
        原因
            虚拟机中没有泛型,只有普通类和普通方法
        类型擦除的关键
                1.从泛型类型中清除类型参数的相关信息,
                2.并且在必要的时候添加类型检查和类型转换的方法。                   
         类型擦除的主要过程如下:
                1.将所有的泛型参数用其最左边界(最顶级的父类型)类型替换。
                2.移除所有的类型参数
        类型擦除带来的问题
                ClassCastException

2. 序列化

01.不需要序列化
        不希望敏感信息被序列化-防止对象的敏感部分被序列化

02.需要序列化 serialization---轻量级持久化
     001.主要应用方面:
            读写磁盘、网络传输的类--方便的存储/传输
             to serialize a Scala class and save it as a file, or send it across a network.
03.Scala 中的序列化
        Scala中的序列化
            trait Serializable extends Any with java.io.Serializable
            Classes extending this trait are serializable across platforms (Java, .NET).
        使用序列化--继承
                extend the Serializable trait 
            语法示例:case class Posting(postingType: Int, parentId: Option[Int], score: Int, tags: Option[String]) extends Serializable
            scala Serializable 实际上就是一个java.io.Serializable的universal trait
            SerialVersionUID的目的是为了检查序列化和反序列化的类是否兼容。
                        般来说可以不显式指定SerialVersionUID
                        需要直接使用序列化来持久化对象,如将训练好的模型存储到文件系统上,就最好指定SerialVersionUID
        序列化以及反序列化
                    二进制串指的是存储在内存中的一块数据
04.使用场景说明
        001.由于引用的sparkConf, sparkContext都是不可序列化的,
                            且都不需要被传送到executor上运行,
                                因此可以用 @transient表示该成员不需要被序列化
                      @transient (private) lazy 
                            其中 @trainsient 可以避免 overhead,lazy 可以第一次被调用时正确地初始化以避免NPE<空指针异常-NullPointerException>

        002.可以序列化
                broadcast, shuffle, action等操作都会使得对象被序列化。
                    使每个被闭包捕获的变量都可序列化,可以避免异常,
                    但是变量非常大时,容易影响性能,以及有可能造成内存泄露。
            序列化实现
                Protobuf、Thrift、Avro
        不可序列化
                    java静态成员变量不会被序列化
                    不要在scala的object中使用var变量,如果确实需要使用var变量,请写在class中
                Task not serializable: java.io.NotSerializableException
                        了解哪些对象不可以被序列化。
                        <1>就是使这些对象对应的类可序列化,
                        <2>或者将这些对象定义在RDD操作算子的参数(匿名函数)中以取消闭包

3. 元与反射

    meta data                 元数据--注解 annotations
    meta programming 元编程
    reflect                     反射
                编译时元编程
                运行时元编程

            编译时反射用于操纵代码
            运行时反射主要用来--极端滞后绑定<extreme  late  bind>
                        加载编译时未知的代码
                        调整语言的语义
    Scala中的反射
            核心库-scala.reflect
            第三方库:
                    编译时反射:scala.reflect.marcos.universe
                    运行时反射:scala.reflect.runtime.universe
                    编译时宏

            核心库
                    scala.reflect.ClassTag :保留被类型擦除去掉信息的工具
                                类型擦除-在实例化参数类型的实例时,不保留类型参数的值
                                ClassTag--一个重要用途是构造出正确的AnyRef子类型的Java数组

4.变量

惰性求值 lazy
        让系统自行决定何时初始化成员的初始值,这是通过在 val 定义前面添加 lazy(懒惰),
        也是说直到你第一次需要引用该成员是,系统才会去初始化,否则该成员就不初始化

断言--断言机制
        带一个参数 表达式 
                assert(condition) 
                将在condition条件不成立的时候抛出 AssertionError。
        assert--带两个参数的表达式
                    assert(condition, explanation) 
                     会测试condition,并且如果条件不成立,会抛出含有指定explanation作为说明的AssertionError。

5.循环的使用

        1.尽量少使用循环或者条件改变变量-update a var using loops or conditions
        2.使用如下的方法
          /** Average the vectors */
            def averageVectors(ps: Iterable[(Int, Int)]): (Int, Int) = {
                val iter = ps.iterator
                var count = 0
                var comp1: Long = 0
                var comp2: Long = 0
                while (iter.hasNext) {
                    val item = iter.next
                    comp1 += item._1
                    comp2 += item._2
                    count += 1
                }
                ((comp1 / count).toInt, (comp2 / count).toInt)
            }

            方式02.
                    不要使用:var sum = 0
                            for (elem <- elements) {
                              sum += elem.value
                            }
                    使用:val sum = elements.foldLeft(0)((acc, e) => acc + e.value)

参考:

    Scala Serialization  http://www.jianshu.com/p/080f18900f62
    spark使用总结 http://www.itnose.net/detail/6528028.html

blogroll

social