Scala笔记

Scala
  -概述: Scala是面向对象和函数式编程的结合,是一门完整的、完全的面向对象的语言,并且依赖JVM为运行环境,需要将Scala代码编译为字节码文件运行在JVM上。
          Scala同样可以通过Java代码实现,Scala的学习是为了推动Spark的学习。
      说明:语言的完整,在任何情况都可以使用,不像mysql只能再查询时才可以使用。
           完全面向对象,对Java中非面向对象的内容采取相应的处理,如对基本数据类型、Static关键字、Void关键字等。
           Scala中的内容都是完全的面向对象,所有的基本数据类型都是对象,所有的运算符都是方法。

  -Scala与Java的关系:
          Java运行原理:先编译,再解释
              '- .java源文件--->编译器(javac)--->.class字节码文件--->JVM(java 不同平台)--->机器指令'
          Scala运行原理:先编译,再解释
              '- .scala源文件--->编译器(scalac)--->.class字节码文件--->JVM(scala 不同平台)--->机器指令'

  说明:
      编译器是根据语言对应的,什么的语言会对应有那种语言的编译器,通过编译器实现该语言的规范。
      由于Scala是基于Java的,可以采用Scala的编译器对Java源文件进行编译,但是Java的编译器不认识Scala所以不能通过Java编译器编译Scala源文件。
      通过class修饰会生产一个字节码文件,通过Object修饰的类编译完后会生产两个字节码文件。
      在类加载的时候如果需要static{}做一些初始化工作程序才会执行,如静态变量的显示初始化,实际上编译后是在静态代码块中赋值的,而final修饰的变量会在通过常量直接赋值不在静态代码块中赋值,
      自己没有写代码块不代表编译器没有用,如果不需要不会执行。

 -Scala程序的运行:
     -Java代码加载到内存中需要通过调用当前类中static的静态主方法。
     -Scala通过伴生对象的方式加载程序到内存,由于没有并static关键字,而是在编译scala源文件的时候会生成两个字节码文件,分别是伴生对象字节码文件和伴生对象所属类字节码文件。
      其中伴生对象所属类字节码文件中就是scala源代码,只有普通的main方法和定义的其他的普通方法,以及一个通过单例实现的静态当前类对象(关键),和静态代码块,
      而伴生对象字节码文件中会创建一个静态的主方法以及其他的静态方法(与伴生对象所属类中的普通方法对应),这个静态的主方法就是程序的入口,
      在这个方法中会通过伴生对象所属类创建的对象去调用伴生对象所属类中的普通main方法以及main方法中的其他方法。
  说明:在scala的主方法中调用其他的方法时,只会在伴生对象所属类的普通主方法中调用,而不会在伴生对象的静态主方法中调用,伴生对象的静态主方法执行
       时会调用伴生对象所属类中的普通main方法,该普通main方法会调用其他的函数或方法,而伴生对象中的其他的静态普通方法是用来提供给其他类调用该方法时使用。

Scala 变量:
  实际使用中声明对象以后都是通过对象的名字去调用方法,而类型只在创建对象时或者声明时使用了一次,所以Scala认为名字比类型重要,名字声明在前。
  变量与常量:变量都指向了内存中的某一个存储数据的地址;常量是具体的数值。final 修饰的变量还是变量,只不该变量对应内存中的地址不可以改变了。
  Scala中变量必须在声明的同时初始化,但是可以省略数据类型会进行类型推断,推断类型必须能够推断出数据的类型才可以。
  可变变量用 Var 修饰,不可变变量用 Val 修饰。
    说明:Val限定只是编译层面的约束,实际上底层还是个变量并没有final。
          常量的运算发生在编译期,编译完直接赋值,只要不超过范围都可以赋值,而变量的运算发生在运行期。
          Val修饰的变量必须直接初始化,不能默认初始化。
          Scala中的变量不存在先声明后初始化,必须声明的同时初始化,要么具体初始化,要么默认初始化。
Scala 字符串:
 Scala中并没有自己的字符串,而是将Java中的字符串该个名字直接使用。
 连接字符串 println(" hello " + World)
 传值字符串 printf(" hello %s\n ", World)
 插入字符串 println( s"hello $World") 
Scala 数据类型:
 Scala是完全面向对象的语言,不存在基本数据类型,有的只是任意值类型和任意引用类型。
 所有的基本数据类型都是 AnyVal类的对象,而所有的引用数据类型都是 AnyRef类的对象。
 说明: Sclal中的空为Nil是Null类的对象。 所有的类类型都是Any类型的子类。
        Null是所有AnyRef的子类,所以不能将null赋值给AnyValue。表示变量声明后,没有指向任何对象,相当于null,
 类型转换:
     隐式转换:隐式转换底层还是Java直接通过基本数据类型进行了自动类型提升。
     强制类型转换:调用类型中的方法,强制类型转换是截取精度,所以会有精度损失。
 说明:Scala是完全面向对象的语言,所有的类型都提供了toString方法,可以直接转换为字符串。
Scala 运算符:
  Scala是完全面向的语言,所有运算符的本质都是方法,数字都是对象,当调用方法时.可以省略。
 说明:Scala中的==和equals是一样的,都是用来比较对象的内容, == 底层还是通过equals实现的并且添加了非空判断,
    如果想比较两个对象的地址用eq方法,底层采用==实现。
    Range方法底层就是用了until,左闭右开{}

Scala 集合:
    对于几乎所有的集合类,Scala都同时提供了可变和不可变的版本:
        'scala.collection.immutable':不可变集合,对集合进行添加或者删除操作的时候,会创建新的集合对象。
        'scala.collection.mutable' :可变集合,对集合进行添加或者删除操作的时候,直接在原来的集合上操作,不会创建新的集合对象。
     存放单值类型:Seq -> 有序,可重复; Set -> 无序,不能重复
     存放键值对: Map -> 键值对的形式存放数据,其中key无序不能重复。
     当调用'map.get'方法的时候,返回的Option类型数据,Option有两个子类型,Some和None,可以帮我们避免对空值进行处理的情况,使用getOrElse函数,给空值赋默认值
     数组: Array、ArrayBuffer
     List:List、ListBuffer
     Set: Set、mutable.Set
     Map: Map
  说明:
      不可变的集合都在Predef伴生类中定义过了,不用导包
      Scala中的集合都继承了Iterator特质,具有可迭代的性质。

Sclal 分支控制:
 Scala中的分支结构有返回值,可以通过变量来接收返回值,默认返回分支中最后一句的结果,如果有多行满足条件会根据这些返回值的上层类型左方为返回值。
 说明:循环的返回值并不都是有值的,可能是Unit即(),如果想要表达式返回具体的内容可以使用yield关键字。
 Scala中的break都是通过抛出异常的方式实现的,break 后的代码不执行,如果想要之后的代码继续执行需要用 Breaks类中的breakable方法将中断的代码块包起来,类似于try。
 Breaks中包含了break和breakable方法,可以通过导类的方式使用 _ 将Breaks中所有的方法导入,使用方法时可以省略包名。
函数与方法:
  方法定义在类体内,函数定义在方法内,没有重载和重写。
  重载可以避免因参数不同造成调用者调用方法的差异。
  <1>函数可以作为值对变量进行赋值
      将一个函数f1作为一个值赋值给另一个函数f2时f2只是一个函数对象,如果想要执行函数,得加()。
      函数参数的个数,如果将函数赋值给另一个函数时,赋值的函数参数个数不能超过22个否则会报错。
  <2>函数可以作为参数声明在其他函数的参数列表
  <3>函数可以作为返回值,通常作为内层函数。
   说明:
       仅声明一个函数而没有调用则函数不会入栈,不会分配栈帧,只有当函数被调用的时候才会进栈,
       外层函数中嵌套了内层函数只起到了声明的作用,并没有调用内层函数,并且内层函数并不在外层函数中。当外层函数执行完后会出栈,
       但是内存函数中调用了外层函数的变量时,该变量不会随着外层函数一同出栈,而是会延长该变量的生命周期,和内层函数闭包,
       待内层函数执行完后一同出栈,如果存在闭包编译器会生成含$anonfun$的字节码文件,存储在磁盘中,以后再调用内层函数会
       根据闭包直接调用外层函数的变量。再通过参数的形式添加到内层函数的参数列表中。
       函数的释放只会释放当前函数在栈中的栈帧所对应的内容,由于函数中声明的函数会产生在方法区,与当前函数的释放无关。
       闭包= 外层函数的变量+内层函数
   函数的参数:
       <1>Scala中的函数参数也存在可变形参,直接在类型后面加*即可。
       <2>可变形参和Java中一样,通常声明在形参列表的最后,每个形参列表只能有一个可变形参。
       <3>Scala中的参数可以有默认值,而且通常将带有默认值的参数声明在后面,或者在调用带有默认值参数的函数时使用带名参数即可。
          注意:带名参数时没有顺序的。
   至简原则:
       <1>Return可以省略,Scala会根据函数体的最后一行代码作为返回值。
       <2>如果函数体只有一行代码,可以省略花括号。
       <3>返回值类型如果可以推断出来,可以省略(:和返回值一起省略)。
       <4>如果有return那么就不能省略返回值类型,不然会使编译器不知道结束当前函数还是主方法。
       <5>如果函数声明Unit,那么即使函数体中使用return关键字也不管用。
       <6>Scala如果期望是无返回值类型,那么可以省略等号,只有返回值类型是Unit的时候才可以省略=。
       <7>如果函数无参,但是声明了函数列表,调用时函数是括号可加可不加。
       <8>如果函数无参但是没有声明函数列表,调用函数时括号一定不可能加。
       <9>如果不关心名称,只关心逻辑的处理,函数名(def)可以省略。
  匿名函数:
      如果只关心函数的执行过程而不关心函数的名称,和返回值类型,这可以只保留函数的函数体,匿名函数通过Lambda表达式实现,通常将一个函数作为参数传递给另一个函数时,通过匿名函数实现。             
  递归方法:
      普通递归:方法的链式调用,存在严重的弊端,方法的链式调用由于外层方法始终不能释放会占用大量的内存空间,当数据量大的时候,会导致栈内存溢出。 
     尾递归:将每次的计算结果作为参数传递给下一层的方法,始终可以释放内存空间,不会等待下层的计算结果,不会导致栈内存溢出问题。
函数柯里化:内层函数直接写在外层函数的后面。
    好处:1.将参数列表的多个参数拆分为多个参数列表,这样参数所表示的含义清晰明确。
         2.减少闭包编写的代码,如果用到外层函数的变量,可以将变量作为内存函数的参数传递过去。    
控制抽象:Scala可以传一个一段代码、逻辑作为参数,分布式计算的基础 ' => Any'。
惰性函数:延迟函数的调用等到真正用到时才会执行。
    函数每次执行后产生的结果不一定会即使的用到,如果执行函数后产生的结果没有用到就无法释放会始终占用内存空间,此时就可以通过
    惰性函数延时函数的执行,等到真正用到所需数据时才会执行。
访问权限:
  Java中的访问权限: Private-本类、default-本类+本包、Protected-本类+本包+子类、Public-任意。
  Scala中的访问权限:Private-本类、Private[包]-本类+本包、Protected-本类+子类、default-任意,就是public。
 说明:方法的访问权限:子类继承父类的protected的方法在子类中子类自己可以调用,其他类不能调用。 类.方法 中 "." 是 "的"。 需要始终明确方法的调用者!

Scala 面向对象:
   Scala 属性:
       Scala中的属性权限默认都是public的,编译后底层Java代码实现是private的,并且提供了类似"get"和"set"方法 <()、_$eq()>
       通过对象.属性的方式获取和修改对象属性时,实际上时调用了Scala提供的类"get、set"方法。
       如果在属性前加'private'修饰符不仅不使底层的属性使私有的,也会使相应的"get、set"方法也私有,导致该属性只能本类使用。
       如果想在Scala中实现真正的get和set方法,需要在属性前加上属性注解 @BeanProperty
       属性的默认初始化 :属性值= _
   
   Scala包:Scala对Java中的包进行了扩展。
     <1>Scala中的类可以和包的物理路径不一致,编译后的文件属于类中声明的包。
     <2>Scala中的Package可以多参声明,用{}包起来。
     <3>Scala中的包可以有层次结构,并且类可以放在包结构中。好处:子包可以直接访问父包的内容。Java中访问父包需要import。
     <4>Scala中的包也是对象,称之为包对象。当前包下的所有Scala类都可以访问包对象中的内容,将当前包下通用的一些内容定义到包对象中。    
     包的作用:
       1.管理类,将不同的类放在不同的包里方便管理 
       2.区分类,可以将同名的类放在不同的包里 、访问权限、编译时类路径要与类中定义包的路径一致
   Scala 'improt':
       Java: 导入具体类、导入    包中所有的类、静态导类、导全类名区分类
           注意:Java中并没有导包,通常说的导包实际使导类。
       Scala: 对Java的import做了拓展。
         <1>导入包中所有的类 'import java.util._' 。
         <2>Scala中的import可以在任意位置使用。
         <3>Scala中可以导包 'import java.util'。
         <4>Scala中可以一行导多个类通过{}括起来。
         <5>Scala中可以屏蔽包中的某些类,'import java.util.{Date=>_,_}',第一个_屏蔽Data类,第二个下划线表示使用该包的其他类。
         <6>Scala中可以给类取别名,'type sqlDate = java.sql.Date' 或者 'import java.sql.{Date=>sqlDate}'。
         <7>Scala中默认从当前包下找类,若从绝对路径查找需要使用 '_root_'。
         <8>默认情况下,Scala会导入一些包和对象,'java.lang._ | scala._ | scala.Predef._' 。
   
   Scala 抽象性: <不具体、不完整的>
       Java:抽象类、抽象方法
       Scala:抽象类、抽象方法、抽象属性。
         抽象类和抽象方法的关系:抽象类中不一定有抽象方法,有抽象方法的类一定使抽象类。
             Scala中继承了抽象类后需要重写抽象类中的抽象属性和抽象方法(补全即可),如果没有重写完该类也是抽象类;如果要重写抽象类中的具体方法需要加'override'关键字。
         抽象属性:有抽象属性的类肯定是抽象类,属性只有声明没有初始化。
         说明:抽象类中 'val'声明的具体属性才能被重写,且需要加override,否则虽然不报错但编译过不去。
              所谓出现属性实际上底层还是实现的抽象方法,抽象属性会默认提供类"get、set"方法,对属性的重写实际上是对这两个方法的重写。      
   Scala 构造函数:
       Scala是完全面向对象和完全面向函数式编成的语言。
         类也是函数,类名就是函数名,类体就是函数体,将这个特殊的函数称之为构造函数。
       Scala中的两种构造函数:
           主构造函数:主要作用就是完成类的初始化
           辅助构造函数:主要作用就是辅助主构造函数进行类的初始化, 'def this(args){}',且辅助构造函数必须直接或间接调用主构造函数。
         构造函数的参数:Scala中可以将类的属性声明在构造函数参数列表中,通过 'val或var'修饰。    
         构造函数的顺序:
             Scala构造函数的定义顺序:被调用的函数构造器必须定义在当前构造器的前面。
             Scala构造函数的执行属性:与Java构造器的执行顺序相同,由父及子,父类构造函数加载完才返回执行子类构造函数。
         构造器私有化:在构造体{}加 'private'即可。
   Scala 方法: 
        Java默认提供的方法:Object类中继承的方法。
        Scala中默认提供的方法:Object类中继承的方法、Predef中默认提供的方法。
            Scala中特殊的方法: "apply"通常会定义到半生对象中,用于创建伴生类对象,并不是只能创建伴生类对象,还可以创建其他类对象,自己定义。
        方法重载:
            定义:方法名相同,形参列表不同(参数类型、参数长度、参数顺序)
            基本数据类型:
                参数列表中存在调用类型相同的方法时,会调用该相应数据类型的方法,如果没有匹配的会类型提升为匹配的。
                byte -> short -> int, 无法提升为char,因为char是无符号的,不能吧带符号的提升为无符号的。
            引用数据类型:
                方法的调用会根据对应参数类型执行相应的方法,没有匹配的类型会自动类型提升,区别于重写后方法的调用。
        方法重写:
            <1>权限修饰符:重写后的方法权限修饰符大于等于重写前方法的权限修饰符
            <2>返回值类型: 基本数据类型要求重写后保持一致,引用数据类型只能是本身或者其子类,重写前void重写后只能为void。
            <3>抛异常类型: 重写后方法抛出的异常类型要小于等于重写前方法抛出的类型,如果方法本身没有抛出异常,重写后的方法不能抛出异常,只能try-cache
            属性:
                子类继承父类以后会继承到父类中所有的属性和方法,私有的属性和方法也会继承到,只是不能使用而已,而且只有方法重写并没有属性的重写,
                子类可以定义和父类相同的属性,并不会重写继承父类的属性,可以理解为子类此时有两个属性,实质上只有一个,本身并不拥有父类继承过来的属性。
                属性于对象不绑定,声明的对象是什么类型就调用什么类型的对象。
            方法:
                当子类中没有重写父类中的方法时,子类一样可以使用父类中继承的该方法。用归用,子类继父类后可以使用其方法,但本质上子类并没有
                该方法。当子类对象调用方法时若自己没有用会调用父类中的方法,而父类方法中有使用到属性时一定时当前类本身的属性即父类自己的属性,
                因为省略了this. 成员方法是和对象是动态绑定的,而静态方法则不绑定。
                方法的调用始终和对象绑定,如果某个方法没有会调用父类的方法,且在调用父类方法的同时方法属于谁用谁的属性。
   Scala 创建对象:
         对象的创建方式:
             <1>通过new的方式来创建对象,特质、私有构造函数不能直接通过该方式创建对象。
             <2>通过apply方法创建对象,伴生对象可以访问伴生类的所有私有内容,并且编辑器可以自动识别'apply'方法。

   Scala 单例模式:
         Scala中伴生对象就是单例,底层用Java通过私有的构造器和静态代码块创建的单例对象.
         Scala中的伴生对象可以访问伴生类中所有的属性和方法,伴生对象只会加载一次,通过伴生对象创建单例对象。
   Scala 特质:
         Java中的接口:
             通过一个特殊的对象,将一些标准或者规范进行封装,这个对象称为接口。
             如果一个类需要按照一定的规范完成一些功能,那么该类就需要实现特定的接口。
         Scala中特质:
             通过一个特殊的对象,将一些类共通的特征提取出来进行封装,这个对象称为特质。
             如果一个类符合某个特质,那么就可以将对应的特质混入到该类中。    
         可以将Scala中的特质理解为Java中的接口,又可以理解为Java中的抽象类:特质可以实现单继承和多实现的效果,通过 'extends'继承和 'with'实现。
             理解为接口: Scala中的特质可以继承特质,特质可以多混入。
             理解为抽象类:Scala中的特质可以声明抽象方法和抽象属性,类也是单继承的。    
         动态混入:
             特质的方便之处在于可以在创建对象的时候再动态混入特质,不需要对源代码做任何修改。    
         说明:Scala中的集合都继承了Iterator特质,具有可迭代的性质。      
   Salal 枚举:
       Scala中的枚举类似Java中的枚举,创建Scala枚举类需要实现Enumeration类. 
       通过声明变量的形式声明枚举变量'var RED = Value(1,"red")'。      
       访问值:  Color.BLUE => red   Color.RED.id => 1    
  Tuple:元组 : 元素组合 ,最多22个元素。 Map是一个对偶元组。
      元组元素的获取:索引'tuple.productElement(0)'、顺序'tuple_.1'
  Scala的集合支持并行处理,但必须时多核CPU,否则还是并发处理。
Scala 异常:
    1. Scala中异常处理的catch只需写一次,也只能写一次。
    2. Catch中对异常的case判断,小类型的异常写到前面,属于模式匹配。 
    3. Scala中没有所谓的运行时异常和编译时异常之分。没有throws关键字,如果明确代码可能有异常,可以通过添加注解的方式声明异常 '@throws[Exception]'。
    说明:拆箱的过程也会发生空指针,当一个对象调用成员方法时,对象为空会出现空指针异常。

Scala 模式匹配:
    1.模式匹配和Java中的 switch case 较像。某些情况下底层就是通过 switch case 实现。    
    2.模式匹配从第一个case分支开始,只要匹配到某个分支会执行相应的代码然后退出(无穿透)。
    3.case _分支应该写到最后,如果写在前面在他之后的分支都会失效。
    4.如果没有case _分支,匹配不上的时候会报错。
  模式匹配类型:常量、类型、数组、列表、元组、对象。
      说明:匹配类型时,模式匹配不考虑集合中的泛型。
           Scala中数组的泛型实际上是数组的类型。
           匹配对象时会调用'unapply'方法进行属性与值的匹配,没有该方法会报错。
           模式匹配时匹配不上会报错。
           对集合中的数据进行map处理时,集合中的元素是对偶元组时,只能给map函数传一个参数,如果想传一个(K,V)的两个参数,需要以模式匹配。
  模式匹配应用:声明变量、循环匹配、函数参数
        声明变量:普通的变量声明后通过tuple的顺序访问变量值的方式不容易辨别、可读性差,可以通过模式匹配的方式声明变量。
        循环匹配:可以在循环时,直接对变量进行模式匹配,符合条件的再执行相应的操作,与循环守卫的功能类似。
        函数参数:对集合进行操作时,比如map操作需要对符合条件的参数进行处理,此时不能直接map处理,需要以模式匹配,匹配符合参数条件的进行相应的处理。          
  Scala 样例类:
    1.样例类通过case修饰。
    2.样例类会提供apply方法,默认将构造器参数作为apply方法的参数。
    3.样例类的构造器的参数默认使用val声明作为属性,如果要修改可用var对参数进行声明。
    4.样例类会提供unapply方法。
    5.样例类默认实现了序列化接口。 
    6.样例类必须声明参数列表,可以无参。 
  Scala 偏函数: 只对集合中符合条件的数据做处理的函数。
      偏函数本质上还是对数据进行模式匹配,匹配上的进行相应的处理,匹配不上的不管,特别的偏函数中的模式匹配匹配不上的数据时不会抛异常。 
      偏函数处理可以避免集合中数据类型不一致的强转问题,仅针对符合条件的数据处理即可,普通方式也能处理如filter,但是需要强转。
      使用偏函数时不能用map,因为使用偏函数对集合等元数据操作后可能会改变数据长度,而map只能改变原始数据的内容不能改变原始数据的长度。 

Scala 隐式转换:
    隐式函数:
         Java中基本数据类型范围小的会自动提升为范围大的,无需进行转换,编译器会完成。
         Scala中无基本数据类型,数值都是AnyVal类型对象。Byte和Int无子父类关系,但是Byte的数值可以赋值给Int,原因事编译器实现了隐式转换。
         隐式函数会在第一次编译出错后,会二次编译查找隐式规则,找到transform隐式函数,就作用到代码是让代码通过。
      隐式函数的用处:给一个对象添加新的方法时,最好的方法就是隐式转换实现。 
      给一个对象添加新的方法的方式:
          <1>给这个类中添加方法 --修改代码,不好
          <2>给这个类的父类中添加方法,继承父类,比直接添加方法好一丢丢。
          <3>创建特质函数,混入特质函数,或者动态混入,代码修改最少。
          <4>声明隐式函数,即普通类中设置普通方法,    通过隐式函数将需要添加方法对象的转换成调用方法所需对象,实际上是new了一个所需方法的对象。         
    
    隐式参数、变量:
        如果想给你个函数参数的默认值进行修改而不改变原来参数的默认值,可以在函数外声明一个隐式变量,并且通过柯里化的形式将转换的变量与默认值声明为隐式的,
        如果调用函数是传递完整的参数,就会使用实参作为值,如果不传则会使用新的默认值,如果想使用修改之前的默认值需要用(),为了可以继续使用之前的默认值,
        隐式参数需要柯里化。

    隐式类:
        -隐式类和普通类+隐式函数的功能一样,隐式类需要加implicit关键字。
        -隐式类的构造参数只能有一个,即需要调用隐式类中方法的对象。
        -隐式类不能是顶级的,必须定义在类、伴生对象、包对象中。
    隐式机制:
        所谓隐式机制就是出现编译错误时,编译器会从当前代码作用域、当前代码上级作用域、当前类所在的包对象、当前对象的父类或父特质中查找对应的隐式转换规则,
        如果找到可以隐式转换的隐式规则,则会执行相应代码,否则二次编译还过不去。
      说明:当前代码的上级作用域和父类属于同一级别,两者只能存在一个,否则会报错。
             隐式函数中相同的转换规则只能有一个,不同的转换规则可以有多个。    
             隐式最直接的方式就是直接导入。

Scala 下划线的作用:
   <1> _可以作为标识符使用
   <2> _可以在函数赋值时使用,表示将函数本身作为值赋给某个变量
   <3> _可以作为匿名函数的参数来使用
   <4> _可以用来导入某个包中所有的类
   <5> _可以在导包的时候屏蔽某些类 
   <6> _可以在定义属性时默认初始化 
   <7> _可以集合中声明泛型,表示为任意类型。
   <8> _可以在模式匹配是匹配没有成功的情况,类似于default 


Hashmap扩容为2的倍数,1.获取再数组中的位置可以通过与运算,2.扩容之后有50%的数据是不需要移动的。
Java中创建一个和类库中冲突的包不能使用,会通过双亲委派机制去检测,防止了外部类对Java核心类的破坏。

ThreadLocal不能解决线程安全问题,用来解决绑定线程的连接。用到时只会创建一个对象,不需要每次创建每次关闭。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值