Java基础总结

来源:互联网 发布:梦里花落知多少网王txt 编辑:程序博客网 时间:2024/05/19 03:16

一、Java语言的基本组成部分
    1.关键字    2.标识符    3.注释        4.常量与变量
    5.运算符    6.语句        7.函数        8.数组

    
--------------------------------------------------------------------
1、Java 是什么?
    1) Sun公司推出的一种编程语言(工具)。
    2) 一种平台   (例如JavaSE,JavaEE,JavaME)

2、Java能什么?
    1)   企业级应用开发(JavaEE)
    2)   移动设备上的定制开发(3G)

3、Java 的历史?
    1) 1995 出世,1996 正式确定推出1.0版本。
    2)。。。。。
    3) 2006 JDK1.6

4、Java 的特性?
    1) 面向对象(客观存在的一切事物理解为对象)
    2) 跨平台 (依赖于JVM)
    3) 简单(相对于C/C++)
    4) 开源
    5) 强大。。。

5、Java 中常用的术语
    1) JDK (java development kit): Java 程序开发包
    2) JRE :Java 运行时环境?
    3) JVM: Java 虚拟机

     JDK=JRE(JVM+类库)+相关开发工具(javac.exe,java.exe,...)

6、Java 平台
    1) JavaSE (标准版):是其他一切平台的基础,主要用于构建桌面型应用(例如office,...)
    2) JavaEE (企业版):主要用于构建企业级应用,例如EBanking,
                                 淘宝,百度,google,.....ERP,BOSS,CRM
                                 OA,.....
    3) JavaME(小型版):面向手机终端应用的开发,。。。。

7、构建了Java应用程序?
    1) 工具:Eclipse (集成开发工具)
    2) 平台:JavaSE
    3) Java程序的后缀名为".java"

    4) 此文件中Java程序的结构?
        1)第一步:定义包(程序所在的目录):package
        2)第二步:定义类(所有业务相关代码都要写到类中):class
        3)第三步:定义方法(特定的功能代码块):main方法(固定结构)
        4)第四步:定义语句(输出语句):System.out.println("....");

            package day01;
            public class HelloWorld{
                public static void main(String args[]){
                    System.out.println("HelloWorld");
                }
            }

    5) 此程序的运行过程?
        HelloWorld.java-->编译(编译器)-->HelloWorld.class-->解释(JVM)-->01101100-->操作系统                

--------------------------------------------------------------------
基本语法

1、Java 程序基本结构?
    1) 定义包 (package):包名自己定义(所有包名小写)
        1.1) package 语句在整个类中只能有一个。
        1.2) package 语句必须放在所有代码的最前面。
        
        主要作用:1.对Java程序进行更好的分类,同一个包的下面不能出现重名的Java类。
                  2.对类文件进行管理。
                  3.给类文件提供了名称空间
                  4.类名的全称是:包名.类名
                  5.包与包之间的类在访问时,被访问的类以及成员都必须public修饰
                     包与包之间访问只有两种权限可以用,public,protected(该权限只能给不同包中的子类使用)
                  6.包也是一种封装形式                                   

    2) 引入其它包中的Java类(import)
        a) import  android.app.Activity;
        b) import  android.app.*;
            (引入app包中的所有类,不包含子包中。)
        c) 一个程序中可以有多个import语句。
        d) 位置:package语句的下面,类的上面。
            其中:包名+类名称之为类全名
        e) 静态导入:导入是指定的类中的静态成员。
           import static java.util.Arrays.*; //导入所有的静态方法
        
        java默认为所有源文件导入java.lang包下的所有类
        
    3) 类(class) :所有功能代码都将写在类中。
        a) 一个程序中可以有多个类。
        b) 一个程序中只能有一个public类
        c) 假如类的名字使用public修饰,那么程序(.java)的名字必须和类相同。
        d) 建议类的名字每个的首字母大写,其它字母小写。例如MainActivity

    4) 方法(特定的功能代码块的封装)
        a) 静态方法: public static void main(String []args){}
        b) 实例方法: public void onCreate(...){}
        c) 构造方法: public MainActivity(){}
            
        方法的具体语法,结构,会放在后续讲解。

    5) 语句
        a) 每条语句必须以分号结尾。
        b) 建议每条语句写一行。
        c) 类,方法,语句之间应该有适当的缩进。
 
    总结: package                                      0个或1个,必须放在文件开始   
          import|import static                         0个或多个,必须放在所有类定义之前
          public class Person| interface Person        0个或1个,public 类 或 接口定义
          class Person | interface Person              0个或多个,普通类或接口定义
          
2、Java 中的注释?
    1) 作用
        a) 对代码的解释说明(提高程序的易读性)。
        b) 对代码进行相应注释(便于调试)

    2) 分类
        a) 单行注释: //
            单行注释一般应用于方法的内部
        b) 多行注释:/* 被注释的内容*/
            多行注释一般用于方法的内部,或注释掉某个方法。
        c) 文档注释:/** 文档说明 */
            文档注释一般用于方法,类,变量等元素的上面,用于对相关代码进行解释,以便于将来生成相关文档。
 
        注释中的相关快捷键的应用:

        ctrl+/   (单行注释)
        ctrl+shift+/ (多行注释)
        ctrl+shift+\ (取消多行注释)

3、标识符
    1)定义: 程序员对程序中各个元素命名时,使用的字母符号的组合。

    2)标识符定义规则:
        a) 由字母,数字,下划线,$符号组成 (a-z 26个英文字母大小写,0-9 数字,_ 下划线,$ 美元符号)
        b) 不能以数字开头。
        c) 不能是Java中关键字。

    3) 标识符定义原则:望文生义

    4) 标志符具体应用:
        a) 定义包名:所有单词小写。
        b) 定义类名:每个单词的首字母大写,其它字母小写。
        c) 定义变量名,方法名: 第一个单词首字母小写,其它单词首字母大写。
        d) 定义常量名:每个字母都大写。

4、关键字
    定义:官方定义的具备特定功能含义的字符。

    例如: package,public,class,static, void ........
----------------------------------------------
基本语法
    备注:1)0或0.0对0以外的任何数求余都将得到0或0.0;
          2)在运算中类型自动提升为运算中最高类型,在计算
          3)在将float|double转型为整型值时,总是对该数字执行截位,如果想要得到舍入的结果,需要使用java.lang.Math中的round()方法。
1、变量
    1) 变量的概念
        a)  对应内存中的一个存储区域
        b)  该区域有自己的名称(变量名)和类型(数据类型)
        c)    该区域的的数据可以在同一类型范围内不断变化
        

    2) 变量在程序中的定义(三个要素)
        a) 变量类型:(例如 int)
        b) 变量的名字:(例如 a)
        c) 变量的作用域:(变量在什么范围有效)
                
        局部作用域:从定义开始,到定义它的代码块({})结束位置
        重合范围之内的局部变量只能定义一次。
        
        例如:   int a;(定义在方法的内部)
        
    3) 变量的赋值
        a) 定义的同时赋值: int m=30;
        b) 先定义后赋值:int m;m=50;
        说明:局部变量在使用前必须赋值,
        
    4) 变量类型
        java是强类型语音,每个变量在定义时,都要明确具体的类型,在内存中分配了不同大小的内存空间。
        基本数值类型最大的区别是:在内存中占用的空间大小不一致.
        
        a) 基本类型(8种)                               取值范围
            a.1) 字节型 (byte) : 1byte等于8bit        -128~127                                  -2的7次方 ~ 2的7次方减去一
            a.2) 短整型(short):2字节     16bit       -32768~32767                              -2的15次方 ~ 2的15次方减去一
            a.3) 整型(int):4字节          32bit          -2147583648~2147583647                    -2的31次方 ~ 2的31次方减去一
            a.4) 长整型(long):8字节      64bit          -9223372036854775808~9223372036854775807  -2的63次方 ~ 2的63次方减去一
            a.5) 浮点单精度(float):4字节 32bit
            a.6) 浮点双精度(double):8字节64bit
            a.7) 字符型(char):2字节      16bit
            a.8) 布尔型(boolean):1字节   8bit

        b) 引用类型
            b.1) 类
            b.2) 接口
            b.3) 数组
        
        整数默认类型为:int        小数默认类型为:double
        
        byte b = 6;
        详情:6为int类型占4个byte,当放入byte类型时,编译器会检查,数值6是否在byte的取值范围之内,如果在,自动把前24位去掉;如果不在取值范围,编译器会报错,
                需要手动转换类型(会造成精确度丢失),编译时期保证语法正确(内存空间在编译期间完成分配),运行时期确定具体值;
             6  int   00000000 00000000 00000000 00000110  内存中存储情况
                byte                             00000110  内存中存储情况
        
        long L = 12345678900L;  12345678900为int类型,已超出int类型范围,加L明确类型
        long L = 123456789;  对于long类型,数据末位加L(可加可不加L)
        
        float f = 2.3f;      对于float类型,数据末位加f,表示单精度存储;必须加f;
        
        自动类型提升:byte b = 4; int x =3;  x=x+b; //在运算中b类型自动提升为运算中最高类型,在计算
        
        强制类型转换:byte b=3;
                      b = b+1;//报错,编译器报错,语法错误
                      b =(byte)b+1;//b+1为int类型,赋值给byte类型,需要强制转换类型(原因:右边是常量,编译器会自动转换,如果有未知的变量,则需要强制转换)
                                     编译时期保证语法正确(内存空间在编译期间完成分配),运行时期确定具体值;
        char类型运算与编码表(ASCⅡ)
            char ch='a'; //a=97 b=98 ...... 一一对应
                         //A=65 B=66 ......
        
    5) 二进制   
        a)二进制:8个bit为一个单位,即byte(1字节)表示一个数据
        b)十进制转换二进制:除以2并取余数
            例如:6-->110
                  6/2=3  余 0
                  3/2=1  余 1
                  1      余 1
        c)二进制转换十进制:乘以2的次幂(任何非零数的0次幂都等于1)
            例如: 110-->6
                  0*2的零次幂+1*2的1次幂+1*2的2次幂=6
                     0       +     2    +    4     =6
    6) 八进制
        a)在二进制的基础上,每三个有效位,以7为晋级;表现是以0开头表示-->0125(85)
        b)0,1,2,3,4,5,6,7
            例如:85-->0125
                  二进制: 01010101
                  八进制: 001 010 101
                            1   2   5
                表现形式:0125
    7) 十六进制
        a)在二进制的基础上,每四个有效位,以15为晋级;表现是以0X开头表示-->0X55(85)
        b)0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f(a-f,对应10-15)字母不区分大小写
            例如:85-->0X55
                  二进制: 01010101
                  八进制: 001 010 101
                十六进制: 0101 0101
                             5    5
                表现形式: 0X55            
    8) 负数进制
        a)负数进制就是正数的二进制取反加一,负数的二进制最高位都是1,正数的二进制最高都是0
             例如: 6  二进制 00000110    -6 1111 1010
            
        b)二进制位都是1,对应的十进制是-1
            11111111 减一 11111110 取反 0000001
            
            
2、常量
    1)常量的概念:是指在程序中通过源代码直接指定的值(表示不能改变的数值)。
    2)常量的定义:                                范围
        2.1) 整数常量                         正、负、0
        2.2) 小数常量
        2.3) 布尔型常量(boolean)            true和false
        2.4) 字符常量(单个的字符和数值)     'a','1'    
        2.5) 字符串常量                     "a","2"
        2.6) null常量                        null          不能赋值给基本类型的变量,表示引用类型变量中保存的内存地址为空,即还未指向任何有效对象
        
3、运算符(运算符运算完都是有结果的)
    备注:1)运算规律:先运算右边,再运算左边
    
          2)自动提升规则:1.所有的byte类型、short类型、和char类型将被提升到int类型,此三类型的任何一个进行算术运算,都会获得一个int结果
                          2.整个算数表达式的数据类型自动到与表达式中最高等级操作数同样的类型(结果类型>=int)
                         (下图所示:位于箭头右边类型的等级高于位于箭头左边类型的等级)
              
            自动类型转换图:byte --> short --> int --> long --> float --> double
                                     char
                            当把任何基本类型的值和字符串值进行链接运算时,基本类型的值将自动类型转换为字符串类型(字符串类型为引用类型)
              例如:byte b1,b2;
                    byte b3=(byte)b1+b2;//byte自动提升到int类型,需要强转类型。              
                            
          3)自加和自减只能用于操作变量,不能用于操作数值、常量;
                例如:5++ 错误  int i=6--; 错误
                      int x = 2; x++;  正确
          4)+除了可以作为数学的加法运算符之外,还可以作为字符串的链接运算符。
            -除了作为减法运算符之外,还可以作为求负的运算符
          5)== 两边的操作数都是数值类型,即使他们的数据类型不相同,值相等,返回true
               例如: 97='a' 返回true
                     5==5.0 返回true
            == 两边的操作数为引用类型时,比较的是内存中对象地址是否相同,是否是同一个对象
            
          6)预算符的结合性和优先级。(java书中67页,运算符优先级列表--后续有时间补充上)             
                
    1) 算数运算符 + - * / %(求余数) ++ --    2%-5 结果是否为负看左边
    2) 赋值运算符 = += -= *= /= %=           ab%2 不是0,就是1
    3) 比较运算符 == != < > <= >=            比较运算符结果都是boolean
    4) 逻辑运算符 & | ^ ! && ||
    5) 位运算符   << >> >>> & | ^ ~          只操作二进制和整数类型(float|double不能运用位运算符)
    6) 三元运算符
    
    1) 算数运算符
        / 1.整数除法会直接去掉结果的小数位,而不是四舍五入的圆整结果
            例如:5/2=2;
          2.除法运算符的两个运算数都是整数类型,则除数不可以为0
            例如:5/0.0 -5/0.0    正确
                     5/0 -5/0 5%0    错误
                
        ++ 自增,对原有的数值进行+1;
           ++a|--a 会先执行运算,再生成值
           a++|a-- 会先生成值,再执行运算
           
           例如:
           ++前   int a=3,b; b=++a; a=4,b=4;//a先本身自增,再赋值;
           后++   int a=3,b; b=a++; a=4,b=3;//运算规律,先运算右边,再运算左边。temp=a;先将a进行临时存储,a=a+1;自增,b=temp;将临时的值赋给b;
    
    2) 赋值运算符        
        int a=3; a+=4;//a=a+4;会自动转换类型
        short s=4;  
              s=s+5;//编译器报错;原理同byte一致
              s+=5;//编译通过,会做自动转换(赋值运算符特性)
              
    3) 比较运算符  运算结果要么是true,要不是false;

    4) 逻辑运算符
        &        AND(与)         false&true        false      两边都是true,结果是true,否则为false;运算式都会参与运算
        |        OR(或)          false|true        true       两边只要有一个为true,结果必然是true;运算式都会参与运算
        ^        XOR(异或)       true^false        true       两边相同为false,两边不同为true
        !        NOT(非)         !true             false      去反
        &&       AND(短路与)     false&&true       false      两边都是true,结果是true,否则为false;当左边为false,后续运算式不在参与运算
        ||       OR(短路或)      false||true       true       两边只要有一个为true,结果必然是true;当左边为true,后续运算式不在参与运算
        
        &和&&的区别:& 两边都参与运算
                     && 当左边为false,后续运算式不在参与运算
        |和||的区别:| 两边都参与运算    
                     || 当左边为true,后续运算式不在参与运算
     
    5) 位运算符(0代表假,1代表真)    
        <<          左移             3<<2=12(3*2*2=12)         乘以2的次幂运算,移几位就是几次幂
        >>          右移             3>>1=1(3/2=1)             除以2的次幂运算,移几位就是几次幂,右移时,原最高位是什么,就补什么。   
        >>>         无符号右移       3>>1=1(3/2=1)             无符号右移,无论最高位是什么,空位都补零
        &           与运算           6&3=2                     
        |           或运算           6|3=7      
        ^           异或运算         6^3=5
        ~           反码             ~6=-7
        
        >> int i = 8;   i>>32 结果为8  
           long l = 8;  l>>64 结果为8
        
        >>>:无符号右移,无论最高位是什么,空位都补零,不用于除以2的次幂运算,只用于截取二进制中某段的数据(把二进制数据改成其它进制的形式)
        &:两个必须都为真,可用于获取二进制中的有效位1
            例如 6&3=2      110
                           &011        
                           ─────
                            010                           
        |:有真就为真
            例如:6|3=7      110
                           |011
                           ─────
                            111
        ^:两边相同为false,两边不同为true,用于解密/加密(6^3^3=6)
            例如:6^3=5     110
                          ^011
                          ─────
                           101
                           
    6) 三元运算符--if语句的简写格式
        格式:(条件表达式)?表达式1:表达式2;
              如何条件为true,运算后的结果是表达式1.
              如何条件为false,运算后的结果是表达式2.
----------------------------------------
分支语句

总纲:1.程序本身是顺序结构,是自上而下一行代码一行代码的去执行的;
      2.语句是控制程序流程的。一条语句就是一个流程控制整体
        例如:if(布尔表达式){}else if(布尔表达式){}...else{} 此语句就是一个流程控制整体,一旦符合判断条件,输出结果,语句就结束了
        
      3.在java程序中,一个单独的分号表示一个空语句;
    判断结构:if
    选择结构:switch
    循环结构:while、do while、for
    
1、if 语句
    语法形式:
        1) if(布尔表达式){}
        2) if(布尔表达式){}else{}
        3) if(布尔表达式){}else if(布尔表达式){}...else{}
    基本规则:总是优先把包含范围小的条件放在前面处理
    
2、switch 语句
    语法形式:
        switch(表达式){表达式返回值的类型只能为byte,char,short,int,enum,String
            case 值:...;
                    break; (break可选)
            case 值:...;
                    break;
            .....;
   
            default:....;
                    break;(可选,没有满足条件的记录时执行这条语句
        }
    基本规则:1.switch(表达式)表达式的值,一旦遇到相等的值,程序就开始执行这个case标签后的代码,不在判断后面的case,default标签的条件是否匹配,除非遇到break,才会结束;
              2.如果所有case标签后的值都不与表达式的值相等,则执行default标签后的代码块;
              
    switch特点
        1) 答案的书写没有顺序
        2) 匹配的答案被执行,一直执行到break结束或者执行到switch语句结束。
         -->通俗理解:匹配成功,直到执行到break关键字时,switch执行完毕,如果没有break,那么后续的case,default都会执行,直到遇见break或者程序执行完毕
        
        例子:  int x=5;
                switch(){
                    case 5:
                        System.out.println("a");
                        //break;
                    default:
                        System.out.println("c");
                        //break;
                    case 3:
                        System.out.println("b");
                        //break;    
                }
                结果:x=5 输出 a c b
                      x=4 输出 c b
                      x=3 输出 b
3、1.if和switch区别
     if可以用于判断数值,也可以判断区间,只要运算结果是boolean类型,都可以进行判断;
     switch用于对固定的几个值,进行判断,判断的值类型有限。
     
     switch效率优于if,当switch中的多个case为连续性数值时(例如:2,3,4,5,6)
   2.if和三元运算符的区别?
     三元运算符是if预计的简写格式,但不是所有的if else都能简写的,运算符运算完必须有结果。
          
day3-2 循环语句

1.for 循环
    结构形式:for(表达式1;表达式2;表达式3){}
              for(初始化表达式;循环条件表达式;循环后的操作表达式){
                    执行语句:(循环体)
              }
        例子:for(int i=0;i<10;i++){
                System.out.println("HelloWorld-->"+i);
              }                           
              表达式1:初始化表达式 (执行1次)
              表达式2:布尔表达式(执行11次)
              表达式3:迭代表达式(10次)
              循环体{}:执行(10次)
        流程:表达式1 --> 表达式2 --> 循环体
              --> 表达式3 --> 表达式2 --> 循环体
              --> 表达式3 --> 表达式2 --> 循环体
              --> ....
        for循环()定义的变量(局部变量)作用域仅在循环大括号中有效,循环体结束时,变量也将释放。
        
    foreach:高级for循环,其实就是增强for循环(底层用的是迭代器)
    
        格式:for(数据类型 变量名:Collection集合|数组[]){
              }    
        
    for与foreach的区别?
        1.foreach用于遍历Collection集合和数组,通常只能遍历元素,不要在遍历的过程中做对集合元素的操作。
        2.foreach循环必须有被遍历的目标,目标只能是Collection或者数组
                
2.while 循环
    结构形式:while(布尔表达式){//循环体 }
    
3.do while 循环
    结构形式: do{循环体}while(布尔表达式); --> 条件是否满足,这个循环的循环体至少会执行1次。

    建议:循环次数确定使用for,循环次数不确定使用while或do while.
    
    最简单的无限循环 1.while(true){};  2.for(;;;){}

4、两个语句:break(跳出),continue(继续)
    4.1) 不带标号
        break; 退出当前循环,不在执行循环
        continue:退出本次循环而执行下一次循环。
    4.2) 带标号(遵循标识符的定义--> out:for(){}-->out命名任意)
        break: 退出带标号的循环,不在执行循环。
        continue:退出本次循环而执行带标号的下一次循环。
    4.3) break:switch和循环语句
        continue:循环语句    
        
5、循环语句嵌套:1外循环控制行数,内循环控制列数
---------------------------------------------
函数(方法)

前言:方法名和参数列表--合起来被称为方法签名,唯一的标识出某个方法

1、函数的定义?
    1)  Java 中的一个起了名字的代码块。
    2)  此函数是对特定功能的一个封装。(例如求某个数的阶乘)
    3)  函数即方法

    例如:  public static int sum(int a,int b){}

2、函数的三要素?
    1)  函数的返回值类型?(例如void,int,float,.......)
    2)  函数的名字 (此名字遵循标识符的规范)
    3)  函数的参数列表 (指的的是()中的参数)

    public void doClick(View view){}

    其中:
    void :返回值类型
    doClick:方法名
    View view: 参数列表 (view 称之为形式参数)

3、函数的组成?
    1) 函数的声明
        a) 修饰符 (例如 public,static)
        b) 函数三要素
        c) 函数允许抛出的异常 (了解)

    2) 函数体 :大括号"{ }"中的内容

    说明:函数体为可选,当没有函数体的方法通常声明为抽象方法(了解)


4、函数中的return语句。
    return 语句在方法中不仅可以代表程序的返回,还可以返回某个值到调用处。
        1)  return; 仅仅代表方法的返回,后续内容不会再执行。
            当方法的返回值类型为void时,可以直接使用return;
            当方法的返回值类型为void时,也可以没有return语句
        2)  return 值; (返回的值取决于方法的返回值类型)
            当方法的返回值类型不是void时,此方法必须有return语句
    
5、函数的调用 (在一个方法中调用另外一个方法)
    1)  必须指定要调用的方法名
    2)  假如方法有参数,必须指定实际参数 (实参传给形式参数)

    例如:doPrint(10);
    
    3)  java调用方法时可以忽略方法返回值。
    
    例如:test(); //返回值类型为int
    
6、函数的重载?
    1) 名字相同
    2) 参数列表不同 (参数的个数,参数的顺序,参数的类型)
    3) 可变参数(长度可变的形参只能处于形参列表的最后,只能有一个,调用一个可变参数的方法时,既可以传入多个参数,也可以传入一个数组,也可以不传一个参数,在方法内可当数组处理)
    4) 模糊参数(重载时,易发生此错。解决:在可变参数之前,都加一个非不变的参数,以便区分)
    5) 递归(一个方法体内调用它自身,递归一定要向已知方向递归)
    
7、函数的参数传递方式?
    1) java中方法的参数传递方式只有一种,值传递:就是将实际参数值得副本(复制品)传入方法内,而参数本身不会受到任何影响。
        注:基本类型:传入值,不会影响。
            引用类型:传入的是指针(即内存地址值),会有影响,操作的是同一对象(同一个数据源)
    2) 涉及基本类型的重载(值传递的规律)
        a.传入的数据类型(实际参数类型)小于方法中声明的形式参数类型,实际参数数据类型就会被提升(逐次向上提升查找)--char类型除外
        b.char类型略有不同,如果无法找到恰好接受char类型参数的方法,就会把char直接提升至int类型,在按照a规则运行。
        自动类型转换图:
            byte --> short --> int --> long --> float --> double
                     char
    
     备注:String引用类型的参数传递可以理解为值传递,
          例如:String s1 = "lucky";
                String s2 = new String("HelloWorld");
                setString(s1);
                setString(s2);      
                System.out.println(s1);// lucky
                System.out.println(s2);// HelloWorld
                    
                private static void setString(String temp){
                   temp = temp+"--->";
                }    
---------------------------------------------
数组

1、数组概念?
    1) 同一种类型数据的集合,数组中所有元素的类型必须是一样的。
    2) 数组对应了内存中的一块连续的区域,此区域一旦定义(数组初始化完成),其大小不能改变(数组长度将不可改变)。
    3) 数组即可以存基本数据类型(默认初始化值:数值类型为0,char:空字符,boolean:false),也可以存引用类型(默认初始化值为null)
    4) 数组本身所属的类型在Java中为对象类型(引用类型),当我们看一个数组时,要把数组看成两个部分,一部分是数组引用,也就是在代码中定义的数组引用变量,
         还有一部分是实际的数组对象,这部分是在堆内存中运行的。
    5) 操作基本类型数组的数组元素时,实际上就是操作基本类型的变量。
    6) java中操作数组的工具类:Arrays
    
        例如:int[] c=new int[10];//默认初始化的值由类型而定int默认为0,长度固定为10,存储的数据类型都是int类型
              
              //协变类型
              Object[] object = new String[2];//new关键字后的元素类型,必须是显示指定的数组元素类型或者其子类的实例(只能是引用类型,基本类型是不行的)。
              Object[] object = new List[2];
              
2、数组的定义以及初始化?(赋值)
    正确的定义方式:
        动态定义:
           int[] c=new int[10];//默认初始化的值由类型而定
        静态定义:
           int[] d=new int[]{1,2,3,4};//此形式类似 int []d={1,2,3,4}
           double m[]={2,3,4,5};//简写的静态定义,在定义数组时,必须同时赋值。
    
    错误的定义方式:
    
        a={1,2,3,4};//简写的静态定义,在定义数组时,必须同时赋值。
    
        int c[]=new int[4]{2,3,4,5};//此时不能指定其长度

3、数组的长度:数组中元素的个数,可以通过.length属性获取

4、数组元素的访问: 通过下标(永远从0开始,到length-1结束)
    m[0]=30;
    m[2]=50;
    m[4]=60;//下标越界

6、数组的遍历
    1)  通过for,....循环
    2)  借助Arrays类:调用其toString()方法
    
7、数组的应用
    1) 选择排序:内循环结束时,最值出现在头角标位置上。
    2) 冒泡排序:相邻的两个元素进行比较,如果符合条件则换位,内循环结束时,最值出现在数组末位。
    3) 折半查找:可以提高效率,但是数组必须是有序的。
    4) 查表法:数据之间存在对于关系,通过关系中一方查询另一方。

8、包装机制、泛型、
    包装机制:基本数据类型自动包装机制对数组初始化器也起作用。
              例如:Integer[] a ={1,2,3,4,5};    
              Integer[] gers = new Integer[]{1,2,3,4};

    泛型:数组必须知道它们所持有的确切类型,以强制保证类型安全。数组与泛型不能很好的结合.              
-----------------------------------------------------------------
二维数组 (特殊的一维数组)

1、数组的定义
     int a[][];
     int [][]b; //建议
     int []c[];
    
2、数组的初始化
     静态定义:
       int[][] d4 = new int[][]{{1,2,3},{3,4,5}}
       int[][] d1 = {{1,2},{3,4,5},{6}}
     动态定义:
       int[][] d2 = new int[2][3];//二维数组d2包含两个一维数组,且一维数组元素个数为3(d4),也可以理解为:定义了一个一维数组,数组类型为int[]类型,数组大小为2个一维数组类型,这2个一维数组的大小为3
       int[][] d3 = new int[2][];//定义了一个一维数组,数组类型为int[],并且数组大小为2,因为没有显示初始化,系统默认初始化为null(把数组看成对象来理解,2个一维数组,就看作2个对象,对象默认初始化值为null)
    
     内存地址表现形式:[[I@ebf7d2   二维数组地址值
                                    [[ 代表二维
                                    I  数组存储类型
                                    ebf7d2 哈希值
                        
                       [I@ebf7d2     一维数组地址值,其它同上                     
3、数组的长度(等于1维的长度,有几个1维数组)
     d4.length=2;
     d4[1].length=3
    
4、数组元素的访问?(通过下标)
     d4[0][0]=1;
     d4[0][1]=2;
     d4[1][2]=5;
    
5、数元素的遍历?
    1)  通过for,....循环
    
-----------------------------------------------------------------
内存结构(重点-简单了解,完成java api部分时,重点分析整合内存)

    java对内存空间的划分:五部分--->栈(私有),堆(共享),方法区(共享),本地方法区(私有),寄存器(私有)。
    
    1.栈(虚拟机栈):java虚拟机栈是线程私有的,它的生命周期与线程相同。虚拟机栈描述的是java方法执行的内存模型:每个方法在执行的同时都会创建一个栈桢用于存储局部变量表、操作数栈、动态链接、方法出口等信息。
                    每一个方法从调用直至执行完成的过程,就对应着一个栈桢在虚拟机栈中入栈到出栈的过程。
                    局部变量表所需的内存空间在编译期间完成分配,当进入一个方法时,这个方法需要再帧中分配多大的局部变量空间是完全确定的,在方法运行期间不会改变局部变量表的大小。
        
         简单理解:  局部变量表:存储的都是局部变量,只要是在方法中和语句里定义的变量都是局部变量,当数据使用完,所占空间会自动释放。
                                细分:a.所有定义在方法中的变量(包括在for循环中定义的)
                                      b.方法的参数变量  test(int a);
                                      c.语句里定义的变量
                                      
    2.堆(java堆):java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例。
                  所有的对象实例以及数组都要在堆上分配(但是随着JIT编译器的发展与逃逸分析技术逐渐成熟,栈上分配、标量替换优化技术将会导致一些微妙的变化发生,所有的对象都分配在堆上也渐渐变得不是那么"绝对"了)    
         
         简单理解:存储的都是实例(对象)---用new创建的
                  1.用new创建的都是在堆内存(对象和数组)
                  2.每个实例都有内存地址值
                  3.实例中的变量都有默认的初始化值,不同类型不一样(int-->0,double-->0.0,boolean-->false,char-->'\u0000')
                  4.实例不再被引用时,会在不确定的时间内被垃圾回收器回收。
                  
    3.方法区:线程共享的内存区域,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译编译器编译后的代码等数据。
     
         简单理解:方法区存放Class的相关信息,如类名、访问修饰符、常量池、字段描述、方法描述等。
    
    4.本地方法区:为虚拟机使用到的Native方法服务。
        
    5.寄存器(程序计数器):当前线程所执行的字节码的行号指示器。字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。
-----------------------------------------------------------------

1、java 程序的入口
    静态主函数:public static void main(String[] args){}
    public:访问权限最大
    static:静态修饰符,此方法为静态方法,静态随着类的加载而加载,不需要对象,直接类名.main访问
    void:不需要返回值
    main:函数名,该名称是固定的,可以被jvm识别
    (String[] args):形参,函数的参数列表,字符串数组类型
    args:arguments的简写,变量名
    
    jvm在调用主函数时,传入的是new String[0]

-----------------------------------------------------------------
day10 -1 编程方式

1、面向过程编程:强调解题的步骤
    通过函数体现,并不断的调用函数执行。程序=算法+数据       

2、面向对象编程:更符合人们看待事物的基本规律
    基于面向过程,将过程进行对象的封装。程序=对象(数据)+消息
    
    两者的差异:1.面向对象是一种更符合人们思考习惯的思想
                2.面向过程更多的体现的是执行者,面向对象中更多的体现是指挥者,指挥对象做事情。
                3.面向对象将复杂的问题简单化了。
        
3、    面向对象的主要特征: 1.封装
                        2.继承
                        3.多态
                        4.static与final修饰符
                        5.抽象类(abstract)与接口(interface)
                        6.内部类
                        
    面向对象的基本特性:1.万物皆为对象。
                            将对象视为奇特的变量,它可以存储数据,除此之外,你还可以要求它在自身上执行操作。                    
                        2.程序是对象的集合,他们通过发送消息来告知彼此所要做的。
                            要向请求一个对象,就必须对该对象发送一条信息。(调用对象的方法)
                        3.每个对象都有自己的由其他对象所构成的存储
                            对象自身内部可以组合其他对象,来创建新类型对象,可以在程序中构造复杂的体系,同时将其复杂性隐藏在对象的简单性背后
                        4.每个对象都拥有其类型
                            每个对象事都某个类的实例
                        5.某一特定类型的所有对象都可以接受同样的消息
                            继承,多态
                            
    对象具有状态(属性),行为(方法)和标识(内存地址)            
         每一个对象拥有内部数据(状态)和方法(行为),每个对象在内存中都有一个唯一的地址(标识)    
        
    类描述了具有相同特性(数据元素)和行为(功能)的对象集合,所以一个类实际上就是一个数据类型。    
    
4、总结
    在java中,除了8个基本类型值以外,一切都是对象
    
Class对象:包含了与类有关的信息,每个类对应的都只有一个Class对象,Class对象就是用来创建类的所有的常规对象的。
           所有的Class对象都属于Class类
     1.Class c=Class.forName("Person");//生成Class对象,会进行类的静态初始化
       Person p=c.newInstance();//必须带有默认的构造器
       
     2.Person.class;//生成Class对象,比上面的forName方法更安全也更高效。
                     不会进行类的静态初始化,被延迟到对(静态方法-变量|构造器|非常数静态域)进行首次引用时才执行。
                        非常数静态域:static final TWO = new Random().nextInt(10);
                          常数静态域:static final ONE = 11;
       
    instanceof与Class的区别?
      1.instanceof保持了类型概念,它指的是--你是这个类吗,或者你是这个类的派生类吗?
      2.==比较Class对象,就没有考虑继承--它或者是这个确切的类型,或者不是。
            
☆☆☆            
对象创建过程(重点--简化):    1.加载Person.class文件进方法区,并进行空间分配
                            2.如果有静态变量,先默认初始化,显示初始化
                            3.如果有静态代码块,要执行,仅一次。---------->静态代码块|显示初始化,谁在前,谁先执行,执行顺序是从上而下
                            4.通过new在堆内存中开辟空间,并明确首地址。
                            5.对对象中的属性进行默认初始化
                            6.调用对应的构造函数进行初始化
                            7.构造函数内部:
                                  7.1 调用父类构造函数super();(默认的存在构造函数第一行)
                                  7.2 实例变量的显示初始化
                                  7.3 构造代码块初始化 ---------->构造代码代码块|显示初始化,谁在前,谁先执行,执行顺序是从上而下
                                  7.4 构造函数自定义内容初始化
                            8.对象初始化完毕后,将地址赋值给P变量。
        
          注意:1.在类中静态变量初始化顺序从上而下,当static{}静态代码块与静态变量同在时,加载初始化顺序一样是从上而下初始化。
                2.在类中实例变量初始化顺序从上而下,当{}构造代码块与显示初始化同在时,加载初始化顺序一样是从下而下初始化。          
                3.在类的内部,变量定义的先后顺序决定了初始化的顺序。

    加载类的两种情况:1.创建此类的第一个对象时
                      2.类名.static方法|变量(非常数静态域(Class有定义))时(第一次时)
    
简单了解(java编程思想中在细看):在本类中不能引用定义在自己之后的变量。
               例如:int i = g(k); ---->此行代码会报错,(向前引用)如果此处是静态变量,则无错误,因为static变量已经初始化完成,非static在对象创建过程中,自调存在不确定性。
                     int k = f();
                     int f(){return 11;}
                     int g(int n){return n*10;}
                    
                
               正确:int i = this.k;   --->赋值为0 i默认初始化为0,显示初始化时也为0;K变量在其之后,此时k仅默认初始化完成,K为0,
                     int i = g(getk()); --->赋值为0 i默认初始化为0,显示初始化时也为0;K变量在其之后,此时k仅默认初始化完成,K为0,
                     int i = g(this.k);
                    
               错误:int i = k;
                     int i = g(k);
                    
5、所有变量(☆☆☆☆☆)            
    1)变量类型
        java是强类型语音,每个变量在定义时,都要明确具体的类型,在内存中分配了不同大小的内存空间。
        基本数值类型最大的区别是:在内存中占用的空间大小不一致.
        
        a) 基本类型(8种)                               取值范围
            a.1) 字节型 (byte) : 1byte等于8bit        -128~127                                  -2的7次方 ~ 2的7次方减去一
            a.2) 短整型(short):2字节     16bit       -32768~32767                              -2的15次方 ~ 2的15次方减去一
            a.3) 整型(int):4字节          32bit          -2147583648~2147583647                    -2的31次方 ~ 2的31次方减去一
            a.4) 长整型(long):8字节      64bit          -9223372036854775808~9223372036854775807  -2的63次方 ~ 2的63次方减去一
            a.5) 浮点单精度(float):4字节 32bit
            a.6) 浮点双精度(double):8字节64bit
            a.7) 字符型(char):2字节      16bit
            a.8) 布尔型(boolean):1字节   8bit

        b) 引用类型
            b.1) 类
            b.2) 接口
            b.3) 数组
        
        整数默认类型为:int        小数默认类型为:double
        
    2)变量性质    
        1.一个类中不能定义两个同名的成员变量(一个是类变量,一个是实例变量也不行)
        2.局部不能与形参同名,局部不能与局部同名(在同一个作用域中,不能定义相同的局部变量名)
        3.局部变量与成员变量重名,局部变量优先
        4.类(静态Field)是先存在,对象(实例Field)是后存在的
        5.类变量是对象的共享数据,进行单独空间的存储(方法区),可以直接被类名调用
        6.静态只能访问静态,非静态可以访问所有。
        
        a) 成员变量(基本类型和引用类型)
            a.1) 实例Field(不以static修饰),简称实例变量
            a.2) 类Field(以static修饰),    简称静态变量(类变量)
            
            基本类型    默认值            引用类型       默认值
            boolean      false             引用           null(常量)  
            byte         0
            short        0
            char         \uoooo
            int          0
            float        0.0f
            double       0.0d
            
        b) 局部变量(基本类型和引用类型)
            b.1) 方法中定义的
                   1.形参:方法签名中定义的变量
                   2.方法局部变量:在方法有效范围内定义的
                   
            b.2) 语句里定义的       
                   1.if语句、switch语句、循环语句...
                    例如:for(int i =0;i<5;i++){}
                    
    3)变量的区别:
    
        成员变量与局部变量的区别:一.定义的位置不同
                                      a.成员变量定义在类中
                                      b.局部变量定义在方法中以及语句里
                                      
                                  二.在加载时间与内存中的存储区域不同      
                                      a.类变量随着类的加载而加载,存储在方法区的类信息中,类变量属于类。类变量只分配内存一次,在类加载的时候(同一个类通常只加载一次)
                                      b.实例变量随着对象的加载而加载,存储在堆内存的对象中,实例变量所属于对象。每创建一个对象,此对象的实例变量就分配一次
                                      c.局部变量随着方法进栈而加载,存储在栈内存的方法中,局部变量所属于方法栈。
                                
                                  三.生命周期不同
                                      a.类变量生命周期最长,随着类的消失而消失。
                                      b.实例变量随着对象的出现而出现,随着对象的消失而消失
                                      c.局部变量随着方法运行而出现,随着方法的弹栈而消失(循环体中|语句中,定义的变量,随着循环体和语句的结束,变量而释放(变量作用域所在的主体决定))
                                      
                                  四.初始化不同
                                      a.类变量随着类的加载而初始化值,并且有默认初始化值(可以被类和对象调用,一般都用类名调用)
                                      b.实例变量随着对象的创建而初始化值,并且有默认初始化值(只能被对象调用)
                                      c.局部变量没有默认初始化值,必须初始化后才可以使用                                      

6、关键字
    1)this关键字
      |--->this.实例变量/实例方法,用于标识实例变量,当与局部变量同名时,必须用this标识。
      |--->this(参数列表);
           |-->应用于构造方法内部,
           |-->用于调用本类其它构造函数
           |-->只能放在构造函数的第一行,初始化动作要先执行
      |-->this就代表对象,哪个对象调用了this所在的函数,this就代表哪个对象
           例如:public class Person{
                     private String name;
                     private int age;
                    
                     public Person say(){
                         System.out.println(age);
                         return this;//返回调用该方法的对象
                     }
                 }
            好处:可以连续调用同一个方法,也可以连续调用其他方法
    
    2)super关键字
       ->应用于方法内部,指向父类内存空间
       ->super(参数列表);访问父类构造方法
       ->super.父类实例属性/父类实例方法
              父类属性和方法必须是子类能继承到的

      this和super用法相似
      this:代表的是对象的引用
      super:代表的是父类的内存空间地址  
    
    3)instanceof关键字
       ->判断某个引用指向的对象是否属于某种类型
         保持了类型概念,它指的是--你是这个类吗,或者你是这个类的派生类吗?
         例如:if(c1 instanceof Car){}
        
7.修饰符
    1)private,default,protected,public,这4个关键字只能修饰成员(变量|函数)或类,不能修饰局部变量。
    
      private(私有)    --->本类的内部
      default(默认)    --->本包
      protected(继承)  --->本包以及子类中
      public(公开)     --->任意包中
    
    备注:java8中default修饰符只能在接口中定义方法时使用,其它无法显示使用此修饰符(默认功能还在)。
    
    2)static
       总结:1.被static修饰的变量和方法独立于该类的任何对象,也就是说,它不依赖类特定的实例,被类的所有实例共享。只要这个类加载,java虚拟机就能根据类名在
              运行时数据区的方法区中找到他们  
             2.public修饰的static变量和方法本质上是全局变量和全局方法,类的实例对象共享
             3.private修饰的static,表示只能在本类的内部使用,不能在其他类中通过类名来引用了(private修饰的成员变量都是如此)            
              
              静态函数调用:类名.静态函数(建议)
                        对象.静态函数(不建议)    
    
          1.修饰实例变量(此变量为类变量或静态变量)
          ->主要用于存储对象的共享的数据
          ->类加载时(进内存),进行(默认)初始化(赋值),且初始化一次
          ->允许在静态代码块中进行重新赋值(显示初始化,但本身也有显示初始化时,执行顺序是从上而下)
          ->通过类名直接访问,随着类的存在而存在,生命周期最长
          ->类中的多个类变量,初始化顺序从上到下
          
        2.修饰方法(此方法为静态方法)
          ->静态方法又称类方法,静态只能访问静态成员,非静态可以访问所有
          ->此方法可以类名直接访问(类.静态方法)
          ->此方法通常应用在工具类中
          ->静态方法没有多态,且能被重写-----------☆☆☆
          ->静态方法中不允许出现this,super关键字-----------☆☆☆
             原理:1)静态是随着类的加载而加载,也随着类的消失而消失
                   2)静态优先于对象存在,被对象共享
                   3)静态无法访问非静态,内部无法书写this,super,对象有可能不存在,this没有任何指向。
            
        3.修饰代码块(静态代码块)
          ->类加载时执行,且执行一次(可以执行系统的初始化操作)
          ->对类进行初始化,且可以对类变量重新赋值
          ->只能访问静态成员
          ->静态代码块的加载顺序,从上而下
             例如:static{}
            
             实例代码块(对象初始化时执行,new几个对象就执行几次)
             {}(又称构造代码块)
             构造代码块可以给所有对象共性的属性显示初始化,定义不同构造函数的共性代码
            
             局部代码块{}
             1.定义在方法里
             2.作用:可以控制局部变量的生命周期,当在方法中定义的局部变量仅在方法中有限的范围使用时,可以定义在局部代码块中,一旦使用结束,将释放栈内存,
                    方法代码将继续顺序执行,减少栈内存的空间。
            
       4.修饰内部类(静态内部类)
          ...内部类时总结,此处就不在说明
       
       5.static 导入
          
    3)final
      1.修饰变量
        ->此变量为常量,只能赋值一次,即可以修饰成员变量,也可以修饰局部变量
        
          局部变量:只能赋值一次,赋值时间和位置没有要求
          成员变量:
              a.静态变量:显示初始化|静态代码块,只能赋值一次。当两者都存在时,静态代码块(位置无论在显示初始化上还是下)赋值会报错
                      显示初始化为主
              b.实例变量:显示初始化|构造代码块|自定义初始化,只能赋值一次。当显示初始化|构造代码块都存在时,构造代码块(位置无论在显示初始化上还是下)赋值会报错
                      显示初始化为主
        不可改变:基本类型来说是其值不可变。
                  对象变量来说是其引用不可变。
      2.修饰方法
        ->此方法不能被重写(重写发生在继承关系中)
    
      3.修饰类
        ->此类不能被继承

      特点:使用final是提高系统安全的一种方式        
        
    4)native:主要修饰方法,本地方法,调用底层代码
    
    5)synchronized(线程安全包含原子性和可见性两个方面,java的同步机制都是围绕着两个方面来确保线程安全的)
      定义:可以保证在同一时刻,只有一个线程可以执行某一个方法或某一个代码块。
      特征:互斥性和可见性、原子性
      作用:1.同步synchronized不仅可以解决一个线程看到对象处于不一致的状态,
            2.还可以保证进入同步方法或同步代码块的每个线程,都看到由同一个锁保护之前所有的修改效果(每调用一次synchronized修饰的方法或者代码块,都会获取一边对内存中最新的数据)  
    6)volatile
      特征:保证可见性,但是不支持原子性
          a)可见性:是指当一条线程修改了这个变量值,新值对于其他线程来说是可以立即得知的。
          
                  普通变量不能做到这一点,普通变量(和volatile变量)的值在线程间传递均需要通过主内存来完成
                    例如:线程A修改一个普通变量的值,然后向主内存进行回写,另外一条线程B在线程A回写完成之后再从主内存进行读取操作,新变量值才会对线程B可见。
    
          b)不支持原子性:基于volatile变量的运算在并发下并不是安全的。
          
              
☆☆☆☆☆c)使用volatile的变量是禁止指令重排序优化。(指令重排序优化会干扰程序的并发执行,它是并发编程中最容易让开发人员迷惑的地方)
             普通的变量仅仅会保证在该方法的执行过程中所有依赖赋值结果的地方都能获取到正确的结果,而不能保证变量赋值操作的顺序与程序代码中的执行顺序一致。
                      
      作用:1.在工作内存中,每次使用V前都必须先从主内存刷新最新的值,用于保证能看见其他线程对变量V所做的修改后的值。
            2.在工作内存中,每次修改V后都必须立刻同步回主内存中,用于保证其他线程可以看到自己对变量V所做的修改。
            3.volatile修饰的变量不会被指令重排序优化,保证代码的执行顺序与程序的顺序相同。
            
            总结:volatile保证了线程在使用时同步更新此变量和同步修改到主内存,并且不会重排序优化
            
      场景:是在多个线程中可以感知实例变量被更改了,并且可以获得最新的值得使用,也就是用多线程读取共享变量时可以获得最新值使用。
      
8.java命令集合
    1.javap -c HelloWorld.class   // -c 标志表示将生成JVM代码
    2.jps // 得到线程id
      jstack -1 3244 // 3244 是线程id,表示此线程下是否有线程死锁
    
-----------------------------------------------------------------
类与对象

1、类与对象的概念
    1) 生活中的类与对象
        类:是客观事物在人脑中的主观反映
        对象:客观存在的一切事物。
    2) 程序中的类与对象
        类:对事物的描述,需要体现属性和行为(成员变量和函数),需要使用class去定义
        对象: 该类事物创建的实例,通过该对象调用具体的属性和行为。

2、类与对象的定义(程序中)
    1) 类的定义(使用class声明)
        1.1)属性 (对应生活中类的特征)
            a) 位置:类的内部,方法的外部
            b) 类型:基本类型或者对象类型
            c) 修饰符:没有static修饰
            d) 称呼:又程实例变量(每个对象都有一份)
        1.2)方法  (对应生活中类的行为)
            a) 位置:类的内部,其它方法外部
            b) 修饰符:没有static修饰
            c) 访问:必须通过对象或对象的引用。

            例如:
                Random r=new Random();
                r.nextInt();//r 称之为一个引用类型的变量
                new Random().nextInt();//通过对象直接访问方法

    2)对象的构建:(借助new 关键字)
        语法结构: new 类的名字(参数列表)/反射
        构建过程:看上述详细的描述,此处就不在说明...
            

    3) 构造函数
        a) 名字与类名相同
        b) 没有返回值类型,但是有默认的return;
        c) 通常用于对类中实例变量进行初始化

        构造函数是一个特殊的函数,此函数会在构建对象时自动调用,具体调用哪一个构造函数,取决于参数列表。
            new Point();
            new Point(10,20);

        构造函数同样存在重载关系,所有的构造函数名字都是相同,参数列表不同。(跟函数的重载规则一致)
        
        每个类中默认就有一个空参数的构造函数,如果类中自定义了构造函数,那么默认的空参数构造函数就不存在了。
        
        细节:1.每个类中可以定义多个构造函数,他们的存在是以重载的形式体现的
              2.构造函数中也是有return语句的,用于结束初始化动作的
              3.构造函数修饰符为private时,用于单例,只能在本类中调用此构造函数.
        
        构造函数与一般函数的区别?
              1.写法不一样(不是重点)
              2.运行上有差别,对象一创建就会调用对应的构造函数,而一般函数是对象创建后,才会运行或调用所需。
        
        构造函数可以和一般函数同名        
        
        构造函数中实例函数有多态---☆☆☆
        
    4) 对象的引用
        a) 自己手动定义
            Point p1=new Point();
            p1称之为对象的引用,它的值指向对象的地址。
            p1=new Point();
            p1=null;
        b) 系统非静态函数中默认提供的(this关键字)
            this关键字:
            |--->this.实例变量/实例方法,用于标识实例变量,当与局部变量同名时,必须用this标识。
            |--->this(参数列表);
                 |-->应用于构造方法内部,
                 |-->用于调用本类其它构造函数
                   |-->只能放在构造函数的第一行,初始化动作要先执行
                 |-->this就代表对象,哪个对象调用了this所在的函数,this就代表哪个对象
                
-----------------------------------------------------------------
封装(高内聚,低耦合)    

1.广义的封装(从业务背景考虑)
    1)一个系统中有哪些模块
    2)一个模块中有哪些对象
    3)一个对象中有哪些属性和特征
    
    广义的封装需要具备一定的业务背景。
    广义的封装从本质上来讲其实在做需求分析。
                
2.狭义的封装(从安全角度考虑)
    1)在类的内部,属性私有化    
    1)在类的内部,方法公开化

    封装原则:1.将不需要对外提供的内容隐藏起来。
              2.把属性都隐藏,提供公共方法对其访问。
              
    利:1.将变化隔开
        2.提供重用性,便于使用,便于维护
        3.提高了安全性(隐藏了实现细节),对外提供访问方式        
              
    体现:1.函数就是一个最基本的封装体。
          2.类其实也是一个封装体    
              
3、访问修饰符(修饰类或类成员)
    1) public:       (任意包中都可以访问)
    2) protected: (本包或子类中)
    3) default (默认):(本包中访问)
    4) private:     (本类的内部)              
              
-----------------------------------------------------------------
继承(1.成员变量 2.成员函数 3.构造函数)    
          
1、类是对象的抽象,继承是类(子类)的在抽象(父类)。              
    ->父类是子类共性体现,子类是父类特性的表示方式              
              
2、程序中的继承在代码中的实现?
    例如:public class BMW extends Car{
    }              

3、继承在程序中的特点
    1).可以多层继承,但不可以多重继承
        继承的同时,实现某个接口,算是另类的多重继承(既保存了多重继承的好处,也把弊端排除了)    
    2).子类继承父类非私有的属性和(实例|静态)方法    -----☆☆☆    
    3).子类不能继承父类中的构造方法,但可以通过super关键字访问父类构造方法
        在子类构造方法中使用super(参数列表)--应该放在第一行,不写,默认有条隐式的super();
    4).子类可以重写父类中继承到的实例方法,也可以重写静态方法,但是静态方法没有多态。-----☆☆☆    
    5).子类要想明确调用父类中被重写的实例方法,需要使用super关键字(super.父类方法)
    6).子类除了可以继承父类的属性和方法外,还可以自己定义属性和方法。
    7).在父类中必须有一个public|protected修饰的构造方法,以便子类初始化调用。-----☆☆    
    
    问题1:子类不能继承父类的静态方法吗?
         答:子类可以继承父类的静态方法,也可以重写此方法,只是此方法没有多态.
                因此建议调用父类的静态方法时。类名.方法名(父名.静态方法|子名.静态方法),静态方法存储在方法区中,子类仅仅持有指向它的引用
                 
           
    问题2:子类继承父类非私有的属性和实例方法,那么是不是每个子类实例都有一份父类的属性,多个子类同时修改父类的静态变量是否会影响其它子类
         答:子类实例都有一份自己从父类继承过来的非static属性(动态绑定到子类上)
                 在创建子类对象时,都会调用父类的构造方法初始化一次父类属性(相当于创建了一个父类对象,只是此对象的引用只有子类实例持有super指向)
             父类的static变量也继承了,但却是多个子类共享,一处变动重新赋值,其他调用得到的值也将随着改变(static成员静态绑定到类上)
                 (静态数据存储在方法区)其实是子类持有父类的引用,同一个引用指向相同的static变量
                
    总结:被static修饰的变量和方法独立于该类的任何对象,也就是说,它不依赖类特定的实例,被类的所有实例共享。只要这个类加载,java虚拟机就能根据类名在运行时
            数据区的方法区中找到他们    
            
4、方法重写(Override)
    1).重写发生在继承关系中
    2).重写的方法需要和父类中的-->方法名字相同|参数列表相同|返回值类型相同
    3).子类重写方法的访问修饰符允许比父类更大,但不能更小
    4).通过关键字super访问父类中的方法
    5).重载:只看同名函数的参数列表
      重写:子父方法要一模一样(静态方法也可以重写,但是没有多态)
    6).重写的目的:允许动态的为父类方法中添加一些行为(子类特有的或新的)  
    7).静态覆盖静态(只能),反之非静态也只能覆盖非静态。-----☆☆☆    

5、继承关系中对象的构建过程
    1)加载父类,加载子类
    2)分配父类空间,分配子类空间
    3)默认初始化父类属性,调用父类构造方法
    4)默认初始化子类属性,调用子类构造方法(显示初始化|构造代码块|自定义初始化)    
    
6、变量:
   规则:
    实例|构造函数中调用:
        1)(this.成员变量)会优先在本类中查找,如何本类中没有,才会逐步向上(父类)查找---通用(父类|子类|接口)
        2)(super.成员变量)此类的直接父类中查找,如果没有,会逐步向上(父类的父类)查找,无,则报错。
    
    静态函数中调用:
        1)(静态变量)会优先在本类中查找,如何本类中没有,才会逐步向上(父类)查找---通用(父类|子类|接口)
    
    
  如果子类中出现非私有的同名实例变量时:
    1)访问本类中的变用this,访问父类中的同名变量用super.变量名
    2)(this.实例变量)会优先在本类中查找,如何本类中没有,才会逐步向上(父类)查找
      (super.实例变量)此类的直接父类中查找,如果没有,会逐步向上(父类的父类)查找,无,则报错。
      
    3)都存在与堆内存中,每个子类实例都有一份父类中的实例属性
       在创建子类对象时,都会调用父类的构造方法初始化一次父类属性(相当于创建了一个父类对象,只是此对象的引用只有子类实例持有super指向)
    4)变量在父类中是private修饰,则子类只能通过父类提供的方法区访问此变量    
    
  如果子类中出现非私有的同名静态变量时:
    1)(this.静态变量)会优先在本类中查找,如何本类中没有,才会逐步向上(父类)查找
    2)(super.静态变量)此类的直接父类中查找,如果没有,会逐步向上(父类的父类)查找,无,则报错。
    
    调用静态变量时,建议:类名.变量名
               
7、函数
   规则:
    实例函数中调用:
        1)(this.成员函数)会优先在本类中查找,如何本类中没有,才会逐步向上(父类)查找---通用(父类|子类|接口)
        2)(super.成员函数)此类的直接父类中查找,如果没有,会逐步向上(父类的父类)查找,无,则报错。
    
    静态函数中调用:
        1)(静态函数)会优先在本类中查找,如何本类中没有,才会逐步向上(父类)查找---通用(父类|子类|接口)
    
    构造函数中调用:
        1)(this.实例函数)会优先在this实例(多态)所在的类中查找,如何本类中没有,才会逐步向上(父类)查找---通用(父类|子类|接口)
        1)(super.实例函数)此类的直接父类中查找,如果没有,会逐步向上(父类的父类)查找,无,则报错。
        
        1)(this.静态函数)会优先在本类中查找,如何本类中没有,才会逐步向上(父类)查找---通用(父类|子类|接口)
        1)(super.静态函数)此类的直接父类中查找,如果没有,会逐步向上(父类的父类)查找,无,则报错。
    
    1)构造函数中当子父类中定义了一模一样的函数,运行结果:子类(实例对象所在的类)的函数在运行(多态的体现)
    
    
8、子父类中的构造函数(子类实例化过程)
    1)子类中所有的构造函数,默认第一行都有一句隐式语句super();默认调用的是父类中的空参数的构造函数(隐式--默认)
    2)当父类中没有空参数的构造函数时,子类必须手动通过super语句形式来指定要访问的父类构造函数(显式--指定)
    3)子类的构造函数第一行也可以手动指定this()语句来访问本类中的构造函数,子类中至少有一个构造函数要么this(),要么是super()语句;
    
    1.子类中的构造函数为什么第一句是隐式的super()语句?
      原因:子类会继承父类中非私有的属性和方法,所有子类在初始化时,必须先到父类中去执行父类的初始化动作,才可以更方便的使用父类中的内容。
    
    2.父类构造函数中是否有隐式的super语句?
      原因:有,只要是构造函数默认第一行都是super();

    java体系在设计时,定义了一个所有对象的父类Object,如果这个类没有显示的指定继承哪个类,那么默认继承java.lang.Object此类(包括数组)  
    
9、继承的弊端
    1).打破封装性
      如何能保留自己想封装的,不让其打破,final修饰符提供安全的一种方式。


总结:1.java体系在设计时,定义了一个所有对象的父类Object,如果这个类没有显示的指定继承哪个类,那么默认继承java.lang.Object此类(包括数组)  
      2.创建任何对象总是从该类所在继承树最顶层的构造方法开始执行,然后依次向下执行,最后才执行本类的构造方法
      3.学习继承体系时,应该先参阅顶层类中的内容,了解这个体系的基本功能,使用这个体系时,创建最子类的对象(看顶层,建底层)    
      4.该使用继承还是组合?-->最清晰的判断办法就是问一问自己是否需要从新类向基类进行向上转型。      
      
☆☆☆
  规则:
    实例函数中调用:
        1)(this.成员变量|函数)会优先在本类中查找,如何本类中没有,才会逐步向上(父类)查找---通用(父类|子类|接口)
        2)(super.成员变量|函数)此类的直接父类中查找,如果没有,会逐步向上(父类的父类)查找,无,则报错。
        
    静态函数中调用:
        1)(静态成员)会优先在本类中查找,如何本类中没有,才会逐步向上(父类)查找---通用(父类|子类|接口)

    构造函数中调用:
       相同:1)(super.成员变量|函数)此类的直接父类中查找,如果没有,会逐步向上(父类的父类)查找,无,则报错。
             2)(this.成员变量)会优先在本类中查找,如何本类中没有,才会逐步向上(父类)查找---通用(父类|子类|接口)
             3)(this.静态函数)会优先在本类中查找,如何本类中没有,才会逐步向上(父类)查找---通用(父类|子类|接口)
                
       不同:1)(this.实例函数)会优先在this实例(多态)所在的类中查找,如何本类中没有,才会逐步向上(父类)查找---通用(父类|子类|接口)            
            
       构造函数中实例函数有多态(总结:编译看本类,运行看子类)
        
-----------------------------------------------------------------
多态(1.成员变量 2.成员函数 )
    
1、体现:父类的引用或者接口的引用可以指向子类对象,所有接口类型的引用变量都可以直接赋给Object类型的变量
      如:Car c1=new BMW();
          Car c2=new BenZ();
    
   好处:提高了程序的扩展性
   
   弊端:通过父类引用操作子类对象时,只能使用父类中已有的方法,不能操作子类特有的方法。

   前提:1.必须有关系:继承|实现
         2.都有重写操作(实例方法)

   对象引用的转型:1.父类引用可以直接指向子类对象(向上转型)
                        如:Car c1=new BMW();
                        
                   2.子类引用不允许直接指向父类对象
                   3.在某些情况下可以将父类引用转换为子类类型,但是前提是父类引用指向的对象必须和要转换类型是一致(向下转型)
                         如:Car c1=new BMW();
                             BMW b = (BWM)c1;
      向上转型 好处:提高了扩展性,隐藏了子类型
               弊端:不能使用子类型的特用方法
               
         注意:无论是向上还是向下转型,最终都是子类对象做着类型的变化   
        
      向下转型 好处:可以使用子类型的特有内容
               弊端:在不明确具体子类对象类型时,容易引发ClassCastException异常,所以为了避免这个问题,需要再向下转型前,做类型的判断

      类型判断:1.instanceof(关键字)
                2.Class      

2、成员变量(调用变量名所属的类中的成员变量)

    多态调用该变量时:
        编译时期:参考的是引用类型变量所属的类中是否有被调用的成员变量,没有,则编译失败
        运行时期:也是调用引用类型变量所属的类中的成员变量

    总结:无论编译和运行都参考等号的左边(编译运行看左边)        

3、实例函数
    
    多态调用该方法时:
        编译时期:参考引用类型变量所属的类中是否有调用的方法,如果有,编译通过,反之则失败。
        运行时期:参考对象所属的类中是否有调用的方法,有,则调用子类;没有,则向上找,调用父类中的。
    
    总结:编译看左边,运行看右边。
    
4、静态函数(静态方法没有多态)
    
    静态函数可以重写覆盖,但是没有多态,调用的都是本类中的。
    
    总结:编译和运行,都参考左边
    
注意:1.实例函数是动态绑定到对象上
      2.静态函数是静态绑定到类上
      3.成员变量和静态函数,编译运行都看左边
        实例函数,编译看左边,运行看右边
        
      静态函数调用:类名.静态函数(建议)
                    对象.静态函数(不建议)      
     
      动态绑定:在运行时根据对象的类型进行绑定。   对象上(后期绑定),下面三个修饰符之外都是动态绑定
      静态绑定:程序执行前执行绑定。               方法符为private,static,final 这些方法没有多态(前期绑定)  
        
-----------------------------------------------------------------
抽象类(abstract)

1、抽象类和抽象方法都需要abstract修饰,有抽象方法的类只能定义为抽象类,抽象类里可以没有抽象方法
2、抽象类不可以创建实例,通常充当具体类的父类(调用抽象方法没有意义)
3、只有覆盖了抽象类中所有的抽象方法后,其子类才可以实例化,否则该子类还是一个抽象类。
4、抽象方法没有方法体
    例如:  public abstract void say();
5、抽象类可以包含Field,方法(普通方法|抽象方法),构造方法,初始化块,内部类(接口,枚举)
    在java类里只能包含Field,方法,构造方法,初始化块,内部类(包括接口,枚举)
   
   构造方法需要交给子类调用(super())
6、abstract|final 不能同时出现在类修饰中,
   abstract|final 不能同时出现在方法修饰中
   abstract|static不能同时出现在方法修饰中
   抽象方法不能用private修饰符
   
   abstract和static同时修饰内部类时,此类可以当作外部抽象类
   
总结:抽象类只比一般类多了个抽象方法,且不能被实例化,其它无变化
     
     子类共性,且实现不变的方法在父类中声明为具体方法
     子类共性,且实现会发生变化的方法在父类中声明为抽象方法
    
     目的:将变与不变分开,不变的定义在父类,变的交给子类重写
           不变:事物的基本功能
           变:每个对象的特有功能

-----------------------------------------------------------------
接口(interface),所有域都自动是static和final。

1、接口是一种特殊的抽象类(纯粹的抽象类)
2、接口中所有的方法都是抽象的,所有的变量都是常量(接口中的成员都是公共的-public)
     方法:默认有public abstract 修饰
     变量:默认有public static final 修饰
    
3、接口中没有构造方法和初始化块,同样也不能直接构建对象,可以包含field(只能是常量),方法(<=Java1.7-->只能是抽象实例方法,不允许定义静态方法),内部类(静态)(接口,枚举)
    以上接口中定义的成员的修饰符默认为public static ,指定也只能public static

4、解决多继承的弊端,将多继承这种机制在java中通过多实现完成了
    弊端:多继承是,当多个父类中有相同功能时,子类调用会产生不确认性
          其实核心原因:在于多继承中功能有主体,而导致调用运行时,不确认运行哪个主体内容。
    
    为什么多实现就解决了此问题?
       答:因为接口中的功能都没有方法体,由子类来明确(重写),并且调用的永远是子类覆盖后的方法(如果多个接口中有相同的功能--就是方法名,子类只实现一个就OK)

5、一个类可以同时实现多个接口,也可以继承某个类的同时去实现多个接口
    如:class A extends Object implements IA,IB,IC{}
    
    接口的出现避免了单继承的局限性
    父类中定义事物的基本功能。
    接口中定义事物的扩展功能。
    
6、类与类之间是继承(is a)关系。
   类与接口之间是实现(like a)关系。
   接口与接口之间是继承关系,而且可以多继承。   

7、接口的思想:1.接口的出现对功能是实现了扩展
            2.接口的出现定义的规则
            3.接口的出现降低了耦合性(解耦)        
            
   接口体现的是规范和实现分离的设计哲学。

8、接口与抽象类的区别?
   1.抽象类是描述事物的基本功能,可以定义非抽象的方法
       <=Java1.7  接口中定义只能是抽象方法,负责功能的扩展
         java1.8  接口中可以定义实例方法(必须default修饰)和静态方法
                
   2.类与类之间是继承关系(is a);类与接口之间是实现关系(like a)
   3.接口体现的是一种规范,抽象方法所体现的是一种模板式设计

9、java8新特性-----☆☆☆(Lambda表达式、streamAPI、接口默认实现等等)
    总结:1.streamAPI、接口默认实现对于Android来说只支持7.0及以上的系统
          2.Lambda表达式 兼容到Android2.3
             Lambda表达式:本质上是一种匿名方法,它既没有方法名,也即没有访问修饰符和返回值类型。
             例如:new Thread(new Runnable(){
                     @Override
                     public void run(){
                     // 处理具体的逻辑
                     }
                   }).start();
                   
       Lambda表达式写法:new Thread(() ->{
                          // 处理具体的逻辑
                        }).start();     
                        
                   Runnable runnable = new Runnable(){
                         @Override
                         public void run(){
                         // 处理具体的逻辑
                         }
                   }            
       Lambda表达式写法:Runnable runnable1 = ()->{
                          // 处理具体的逻辑
                         }                
     
     凡是只有一个待实现方法的接口,都可以使用Lambda表达式的写法。
    
    
    1.接口中可以定义静态方法
       Java库中的一个常见情况是,对于某些界面Foo,将会有一个辅助实用程序类Foos,它带有用于生成或使用Foo实例的静态方法。
       现在静态方法可以存在于接口上,在许多情况下,Foos实用程序类可以消失(或者被做为包私有),而其公共方法在接口上。
        
       例如:
         public static <T extends Comparable<? super T>>Comparator<T> naturalOrder() {
               
               return (Comparator<T>)Comparators.NaturalOrderComparator.INSTANCE;
         }    
    
    2.接口中可以定义默认(default)方法,必须default 修饰方法  
       例如:
       public default void forEach(Consumer<? super T> action) {
            Objects.requireNonNull(action);
            for (T t : this) {
                 action.accept(t);
            }
       }
    
    3.为什么默认方法不能覆盖equals(), hashCode(),和toString()---优先级:子类--->父类--->接口
      
      1)接口中定义的默认方法和类中定义实例方法(同名,参数列表一样),运行的是类中的实例方法------☆☆☆      
      2)接口不能为Object类中的任何方法提供默认实现。特别是equals(), hashCode(),和toString()
      3)当调用默认方法时,会更难理解。现在很简单:如果一个类实现了一个方法,总是胜过一个默认实现。由于所有接口实例都是对象,
        所有接口实例都有非默认的equals(), hashCode(),和toString()。因此,在接口上的这些默认版本总是无用的,它也可以不编译
    
    4.功能接口
       含义:如果一个接口只定义一个抽象方法,它就是一个功能接口(接口中除了只能定义一个抽象方法,其它没有什么变化)
             
      @FunctionalInterface:放在接口上,声明此接口是一个功能接口。如果接口定义中有超过一个抽象方法的,将会报错,拒绝编译
    
补充:1.实现接口与继承父类相似,一样可以获得所实现接口里定义的常量,方法(抽象,默认),内部类(接口,枚举)
        常量:
             规则:1)(this.常量)会优先在this实例所在的类中查找,如何本类中没有,才会逐步向上(接口)查找---通用(父类|子类|接口)
                   2)子类继承的父类和实现的接口,两者中有相同的常量,子类报错(不明确的数据),需要再子类重新定义此常量
                   3)父类和接口在调用变量时,如果自身类或接口中没有定义此变量,只会向上查找是否定义此变量,无,则报错
     
        函数:
             规则:1)(this.实例函数)会优先在this实例所在的类中查找,如何本类中没有,会去父类中查找,如果父类中没有,才会去(接口)查找
                        优先级:子类--->父类--->接口
                   2)接口中的静态函数无法继承,只能接口名.方法名 调用        
                   3)子类无法明确指定接口中的默认方法和常量(不能使用super)

      2.所有接口类型的引用变量都可以直接赋给Object类型的变量
    
继承和接口--区别:    
      继承规则:      
          实例函数中调用:
              1)(this.成员变量|函数)会优先在本类中查找,如何本类中没有,才会逐步向上(父类)查找---通用(父类|子类|接口)
              2)(super.成员变量|函数)此类的直接父类中查找,如果没有,会逐步向上(父类的父类)查找,无,则报错。
        
          静态函数中调用:
              1)(静态成员)会优先在本类中查找,如何本类中没有,才会逐步向上(父类)查找---通用(父类|子类|接口)

          构造函数中调用:
              相同:1)(super.成员变量|函数)此类的直接父类中查找,如果没有,会逐步向上(父类的父类)查找,无,则报错。
                    2)(this.成员变量)会优先在本类中查找,如何本类中没有,才会逐步向上(父类)查找---通用(父类|子类|接口)
                    3)(this.静态函数)会优先在本类中查找,如何本类中没有,才会逐步向上(父类)查找---通用(父类|子类|接口)
                
              不同:1)(this.实例函数)会优先在this实例(多态)所在的类中查找,如何本类中没有,才会逐步向上(父类)查找---通用(父类|子类|接口)            
            
            构造函数中实例函数有多态(总结:编译看本类,运行看子类)
       
      接口规则:
          常量:1)(this.常量)会优先在this实例所在的类中查找,如果本类中没有,才会逐步向上(接口)查找---通用(父类|子类|接口)
                2)子类继承的父类和实现的接口,两者中有相同的常量,子类报错(不明确的数据),需要再子类重新定义此常量
                3)父类和接口在调用变量时,如果自身类或接口中没有定义此变量,只会向上查找是否定义此变量,无,则报错      
                
          函数:1)(this.实例函数)会优先在this实例所在的类中查找,如果本类中没有,会去父类中查找,如果父类中没有,才会去(接口)查找
                        优先级:子类--->父类--->接口
                2)接口中的静态函数无法继承,只能接口名.方法名 调用            
                3)子类无法明确指定接口中的默认方法和常量(不能使用super)

-----------------------------------------------------------------                
内部类

1、实例内部类
    1)定义在类的内部,方法的外部
    2)没有static修饰
    3)允许访问外部类中的所有成员,包括私有
    
        之所以可以直接访问外部类中的成员,是因为内部类中持有一个外部类的引用。
        格式:外部类名.this
        
        静态内部类不持有外部的引用,而是直接使用--外部类名.
    4)内部类对象依赖于外部类对象
        格式:外部类名.内部类名 变量名=new外部类对象.new内部类对象
              Out.Int in = new Out().new Int();
    5)在成员位置上,可以被成员修饰符所有修饰
       如:private:将内部类在外部类中进行封装
           protected|public  不多见
                                           
  总结:实例内部类可以当作实例成员来理解,实例内部类(加载的是.class文件)在外部类加载内存时并没有随着一起加载进来,当具体使用时才会加载进来。

  注意:1.非静态内部类中不允许定义静态成员(变量,方法,静态内部类),仅允许在非静态内部类中定义静态常量(static final)  
        2.当内部类中定义了静态成员,该内部类必须是static的
        3.当外部类中的静态成员访问内部类时,内部类必须是static
        
2、静态内部类
    1)定义在类的内部,方法的外部
    2)使用static修饰符
    3)只能访问外部类的静态成员
    4)构建静态内部类对象
        格式: 外部类.内部类 变量名 = new 外部类.内部类();
              Out.Int in = new Out.Int();
   
  总结:1.当使用静态内部类时,才会加载进内存,也可以理解就是一个外部类
        2.静态内部类可以包含静态成员,也可以包含非静态成员。

3、局部内部类
    1)定义在成员函数的内部
    2)只能访问方法范围内,被final修饰的局部变量(<=java1.7)(java1.8无需final修饰局部变量,也可调用)
    3)可以访问外部类的所有成员(实例函数),只能访问外部类的静态成员(静态函数)
    4)不能使用public|private修饰类
    
  总结:当使用到局部内部类时,才会加载进内存。
 
4、匿名内部类(一样持有外部类对象引用)
    1)其实就是一个带有内容的子类对象(核心)
    2)匿名内部类其实就是内部类的简化形式,也是特殊的局部内部类
       实例函数:允许访问外部类中的所有成员,包括私有|也可以访问方法范围内的变量
       静态函数:只能访问外部类的静态成员,包括私有|也可以访问方法范围内的变量
    3)前提:内部类(想要简化书写的这个类)必须要继承父类或者实现接口
    4)内部类中一般方法不要过多,阅读行会很差。    

    补:1.在静态方法中,匿名内部类是无法访问非静态成员的
        2.凡是简化的,通常都有局限。
           例如:匿名对象,匿名内部类...
    
5、内部类的延伸:内部类时可以继承或实现外部接口的  
   
   
   补:public class SubClass extends Out.In(非静态内部类){
               //显示定义SubClass的构造方法
               public SubClass(Out out){
               //通过传入的Out对象显式调用In的构造方法
                     out.super();
               }
       }
       当创建一个子类时,子类构造方法总会调用父类的构造方法,因此在创建非静态内部类的子类时,必须保证让子类构造方法可以调用非静态内部类的构造方法,调用非静态内部类
         的构造方法时,必须存在一个外部类对象。

6.内部类标识符(内部类class文件的命名规则)
    规则:外围类的名字,加上"$",再加上内部类的名字。
          匿名内部类,编译器会简单地产生一个数字作为其标识符。
        
总结:1.内部类无论定义在什么位置,当使用到内部类时,才会加载进内存
      2.内部类访问外部类中的成员,是根据内部类所在位置所持有外部类的引用(访问外部类的所有成员)|持有外部类名(访问外部类的静态成员) 来限制其访问权限的    

      3.在继承中实例内部类和静态内部类,当作实例变量和静态变量看作。
              1)(this.成员变量|函数)会优先在本类中查找,如何本类中没有,才会逐步向上(父类)查找---通用(父类|子类|接口)
              2)(静态成员)会优先在本类中查找,如何本类中没有,才会逐步向上(父类)查找---通用(父类|子类|接口)
              
-----------------------------------------------------------------                
Object类
1.所有类的直接或间接父类
       例如:class A{}
              等于
             class A extends Object{}
    Object类它提供了对象中常用的一些方法,当我们定义某个类时,可以直接使用或重写Object的方法

2.toString();此方法输出对象的地址表现形式
    -->通常可以对此方法进行重写,输出对象中的某些内容。

  getClass();此方法返回的是对象的类型(Class)    
      -->通过Class的getName()方法获取对象的类全名。
    -->也可以比较此对象所有的类型
    
        例如:Person.class
              Class c = p.getClass();
              Stirng name = c.getName();
 
  equals();默认比较对象的地址。
    -->一般重写的目的是比较对象的内容

-----------------------------------------------------------------        
常用API--基本数据类型--对象包装类(对应8种基本数据)

总:1.在JDK1.5自动装箱时,如果数值在byte(-128~127)范围之内,(Byte,Short,Integer,Long)不会新创建对象空间,而是使用原来已有的空间(看源码,有缓存)
          在基本数据对象类型中有本类对象常量缓存数组(-128~127)
    2.相同的两个基本对象类型比较时(Byte,Short,Integer,Long,Boolean,Chacter),通过valueOf()方法生成的对象,并且数值在常量池范围内,值相同,返回true。
         例如:Integer ger1 = Integer.valueOf(11);
               Integer ger2 = Integer.valueOf(11);
               
               ger1==ger2//true,此两个对象引用指向的是同一个对象(常量缓存数组)
               
    3.某个基本数据类型在于某个数据对象类型比较时,系统会默认的把基本数据对象类型转换为基本数据类型进行比较,比较的是2个数值。
         例如:Integer ger1 = Integer.valueOf(11);
               long lon = 11L;
               float flf = 11.0f;//必须加F,小数默认为double
               
               ger1==lon;//true
               ger1==flf;//true   
    4.==两个操作数,都是数值类型,即使他们的类型不同,值相等,则返回true。
         例如:Long l = 100L;             Long l = 100L;//必须加L,整数默认为int
               int  i = 100;              long g = 100L;
               l==i;//true                l==g;//true

               97='a' 返回true            5==5.0 返回true
    
1、 基本数据类型         对象类型               常量池
       byte                Byte                -128~127
       short               Short               -128~127
       int                 Integer             -128~127
       long                Long                -128~127
       float               Float  
       double              Double
       boolean             Boolean             true,flase    -->valueOf();传入的字符不是true,那么一律返回false
       char                Character           128字符(0~127)-->此处有待在查阅下资源?
    
2、特点:用于基本数据和字符串之间进行转换
    1)字符串--->基本数值   
        解析方法:   1.int         Integer.parseInt(String temp); //返回基本类型  字符串--->基本数值    
                     2.Integer     Integer.valueOf(String temp);  //返回对象类型  字符串--->基本数据对象(有常量缓存 ,数值在(-128~127),直接去常量数组中取对象;不在,则new)    

                     只有Character没有解析方法(不用,String本身就是final 字符数组存储--看源码)
    
    2)基本数值--->字符串
        解析方法:34+""
                  String         String.valueOf();//内部用的是Integer.toString(i);
                  String         Integer.toString(i);
                  String         Long.toString(l);
                                 ...
    3)基本数值--->包装对象
        解析方法:1. new Integer(111); new Long(111);.....
                  2. Integer  valueOf(int i);
                  
3、整数的字面值(3种)
      int m1=10;//10进制
      int m2=010;//八进制 (以0打头)
      int m3=0x41;//16进制(0x打头)    
    
-----------------------------------------------------------------    
常用API-2 时间相关类                      
1、Date (这个类中的很多方法已经过时)
2、Calendar(建议使用Calendar获取系统时间中年月日....)
3、DatePickerDialog
4、TimePickerDialog
5、SimpleDateFormat (负责日期和字符串之间的相互转换,求两个日期的天数间隔,时间间隔...)
6、Math(加、减、乘除、开方、四舍五入,)
7、Random(随机数)
8、BigDecimal (银行中常用)
9、System
    1)不需要实例化,都是静态的属性和方法
    2)out对应标准输出流(显示器),int属性对应的是键盘。
    3)获取一些系统信息,如:特定字符,换行符...

-----------------------------------------------------------------    
字符串(String)    
    前言:1.String|StringBuffer|StringBuilder  三者底层实现都是char[]+相关操作。
          2.String对象后面跟这一个+号,而再后面的对象不是String,编译器会试着将this转换成一个String(通过调用this上的toString()方法)
          3.当字符串链接(+|+=)时,如果有未知的链接数据,那么jvm都会创建一个StringBuilder对象来生成此次的String对象。
          
1、String 类:1.字符串都是对象
              2.一旦初始化就不可以被更改(内部是private final char[])存储,所有String对象是不可变的.
              3.通过String类的构造函数,可以将数组(byte,char,int)转换成字符串。
           
    功能: 1.获取 2.判断 3.转换 4.切割 5.替换 6.比较 7.去除空格

2、StringBuffer:线程安全类(底层char[]数组来存储)    
     1.是一个字符串缓冲区,其实就是一个容器。
     2.长度是可变的,任意类型都行(是将任意数据都转成字符串进行存储)
     3.容器对象提供很多对容器中数据操作功能(添加,删除,查找,修改)
     4.最后拼接成一个字符串(toString())
    
    StringBuffer和StringBuilder的区别?
    StringBuffer:线程同步,多线程访问安全。
    StringBuilder:非同步的,单线程访问效率高。
    
3、字符串比较
     规则:1.在编译时期,可以确定下来的字符串,进行比较(==),相同?返回true,反之false
           2.当字符串链接(+|+=)时,如果有未知的链接数据,那么jvm都会创建一个StringBuilder对象来生成此次的String对象。
           
          例如:String s1 = "lucky";//编译时期可以确定下来
                String s2 = "luc"+"ky"; //jvm直接是常量池中取,无其他操作
                s1==s2//true
            
                //查看jvm字节码发现,编译器自动创建了一个StringBuilder对象,用以构造最终的String,并为每个字符串调用一次append()方法,最后toString()生成结果
                "lu" append到StringBuilder中
                "ck" append到StringBuilder中
                "y"  append到StringBuilder中
                最终StringBuilder的toString()生成一个String对象

                String s3 = "lu"+"ck"+String.valueOf("y");//编译时期无法确定下来
                s1==s3//false

                String s4 = new String("lucky");//编译时期无法确定下来
                s1==s4//false
    
       更深入的理解:常量池的存在,以及jvm字节码行为。
       
4、编译器行为
   1)String对象后面跟这一个+号,而再后面的对象不是String,编译器会试着将this转换成一个String(通过调用this上的toString()方法)
      例如:本类中重写toString()
         public String toString(){
             return "lucky-->"+this;//此处会产生递归。
         }
        
5、Formatter类(格式,类型转换)(--->String.format())
    在java中,所有新的格式化功能都是由java.util.Formatter类处理
    例如:formatter.format("%s The Turtle is at (%d,%f)",name,x,y);    
          //结果:lisi The Turtle is at (3,4.0)
          
          %f 字符串类型
          %d int
          %f float|double
          ...

6、注意事项
    1.同步synchronized代码块都不使用String作为锁对象.
    2.
    
-----------------------------------------------------------------    
异常(Throwable)        
前言:1.java中所有的对象都是用来处理数据的,异常已不外如此,只不过此类对象主要用于处理程序中的错误信息。

1、定义:java运行时期发生的问题就是异常(系统级异常Error|应用级异常Exception)

    Throwable:异常的起点,是所有异常信息的父类。
    Error(直接子类):系统级错误,通常发生后不会有针对性的处理方式。
         |-->Error的发生往往都是系统级别的问题,都是Jvm所在系统发生的并反馈给JVM的,无法针对处理只能修正代码。
    Exception(直接子类):应用级别(程序级)的错误,可以有针对性的处理方式。
         |-->Exception(检查异常):必须处理(处理手段:要么捕获,要么继续抛出)
         |-->RuntimeException(非检查异常):可以不处理,报错只能修改代码。    
        
2、异常的应用
    条件满足,功能已经无法继续运算,这时,必须结束功能,并将问题告知给调用者,这时就需要通过异常来解决。
    
    如何使用?1.自定义异常:创建一个异常对象,封装提供信息。
              2.声明(抛出):将问题标识出来,报告给调用者。格式:throws 异常类型(位置:方法名后,{}前)
              3.捕获:java中对异常有针对性的语句进行捕获(try{}catch语句);throw可以用在函数内,抛出异常对象,并可以结束函数(结束程序);格式:throw 异常对象
        
3、自定义异常
    1.目的:对系统错误信息进行更加明确的界定。
    2.编写:继承Exception和RuntimeException,在自定义类中构造方法中,调用super()或父类带参数的方法,把自己想要传递的错误信息传递过去就行(具有可抛性和操作异常的共性方法)

    |-->继承Exception和RuntimeException的区别?
        1.继承Exception为检查异常,在编译时,检查语法时会发生错误,因此此异常必须在代码内部作出处理,要么捕获,要么声明抛出。
        2.RuntimeException为非检查异常,此异常不是功能本身发生的异常,而是调用者传递参数错误而导致功能运行失败,这时也是问题,需要通过异常来体现,此异常不用声明出来。
        
        声明的目的:是为了让调用者进行处理。
        不声明的目的:不让调用者进行处理,就是为了让程序停止,让调用者看到现象,做出修改(对代码进行修正).

4、异常的分类
    1.编译时异常:编译器会检查的异常。(检查异常)---必须处理(声明和捕获)    
    2.运行时异常:编译器不会检查的异常.(非检查异常)---可以不处理,也可以处理
    
    声明和捕获
       声明:将问题标识出来,报告给调用者,如果函数内通过throw抛出了编译时异常,而没有捕获,那么必须通过throws进行声明,让调用者处理(调用者可以捕获,或者继续声明抛出)☆☆☆
       
           格式:throws 异常类型(位置:方法名后,{}前);例如:say() throws Exception{}
        
       捕获: java中对异常有针对性的语句进行捕获。
            try {
               需要被检测的语句或异常
            } catch (异常类 变量) {//对于声明多个异常的方法,在处理时,需要定义多个catch与之对应,检测范围从小到大,父类放在最后一个catch
               异常的处理语句。// 1.不处理或者仅仅打印异常信息 2.抛出运行异常 3.抛出编译时异常(Exception),不建议如此,因为还要在方法上做声明处理。
            }finally {
               1.try代码块不管有没有异常,此代码块都会执行
               2.通常用于释放资源(例如:io流关闭,数据库链接关闭...)
               3.唯有一种情况下finally语句才不会执行,当执行到System.exit(0);因为虚拟机已经关闭               
            }
              
5、throw和throws的区别?
    1.throw用在函数内
      throws用在函数上
    2.throw抛出的是异常对象
      throws用于进行异常类的声明,后面异常类可以有多个,用逗号隔开    
      
6、finally什么使用?
    1.只要程序中使用到了具体的资源(数据库链接,Io资源,网络连接Socket等)需要释放,都必须定义finally中
    2.不管问题发生与否,指定程序都需要执行时,就定义finally中
    
7、try catch finally组合方式
    1.try{}catch{} //对代码进行异常检测,并对检测的异常传递给catch处理(异常捕获处理)
    2.try{}finally{} //对代码进行异常检测,检测到的异常后因为没有catch,所有一样会被默认JVM抛出(异常是没有捕获处理的,但是功能所开启资源需要关闭,所以finally)
    3.try{}catch{}finall{} //检测异常,并传递给catch处理,并定义资源释放
    4.try{}catch,catch2...

8、异常在继承或实现中的使用细节
    1.子类在覆盖父类时,如果父类的方法声明异常,子类只能声明父类异常或该异常的子类,或不声明。
    2.当父类方法声明多个异常时,子类覆盖时只能声明多个异常的子集。
    3.当被覆盖的方法没有异常声明时,子类覆盖时是无法声明异常的。
      
     问题:接口中没有声明异常,而实现的子类覆盖方法时发生了异常,怎么办?
          答:无法进行throws声明,只能try,catch捕获,万一问题处理不了,那么catch中继续throw抛出,但是只能将异常转换为RuntimeException抛出    

 例子一:   Person{
              public void say(){
                 throw new 运行时异常对象(RuntimeException);//可以不处理,但是会结束程序
              }

              public void say(){
                 throw new 编译时异常对象(Exception);//必须处理,处理方法 1.声明 2.捕获
              }
              
              // 1.throws Exception;声明抛出,调用者,必须做出处理
              // 2.捕获try{}catch(){
                         //处理自定义  1.只要throw异常对象(运行时|编译时),都结束程序(前提是都不捕获处理),
                                                运行时异常:程序直接退出    
                                                编译时异常:调用者没有作出try代码块处理。一路声明到main方法,程序结束
                                                    
                                       2.其他处理,则程序继续运行。
                       }

         }
    总结:运行时异常|编译时异常,程序流程-->视处理的情况而定。    
        
 例子二:   int show(int num){
              try{
                 if(num<0){
                    throw new Exception();
                 }
                 return 4;
              }catch(Exception e){
                  System.out.Println(e.toString());
                  return 200;
              }finally{
                  System.out.Println("finally run");
                  return 100;
              }           
           }        
           调用show方法传入大于0的值,运行结果:finally run
                                                返回100
           因为在try代码块中,当执行return 4这行之前,一定要执行finally{}里的代码,而finally里有return 100;此时已经return方法结束,就执行不到return4语句了
           
   总结:无论try{}或catch{}当执行到return语句之前,一定会执行finally{},如果finally{}中有return关键字,函数就此结束(finally中有能结束该函数功能的语句,就以此结束-->return|异常)
                                                                  
9.java7新特性
    1.一个catch块可以捕获多个类型的异常
      a.捕获多种类型的异常时,多种异常类型之间用竖线(|)隔开
         例如:catch(RuntimeException|Excetpion e){}
      b.捕获多种类型的异常时,异常变量有隐式的final修饰,因此程序不能对异常变量重新赋值
    
    2.try(
       声明、初始化需要关闭的资源,try语句会自动关闭这两个资源
       BufferedReader br= new BufferedReader(new FileReader("AutoCloseFile.java"));
       ....多个对象资源       
      ){}catch(){}
    备注:这些资源实现类必须实现AutoCloseable或Closeable接口,实现这两个接口必须实现close()方法      

-----------------------------------------------------------------
1、什么是java内存模型?(深入理解java虚拟机--第五章高效并发)

   答:java内存模型的主要目标是定义程序中各个变量的访问规则,即在虚拟机中将变量存储到内存和从内存中取出变量这样的底层细节。
       此处的变量是指:实例字段,静态字段和构成数组对象的元素(线程共享),不包括局部变量和方法参数(线程私用)。
       
   先行发生原则:java内存模型中定义的两项操作之间的偏序关系(默默的保证了程序的有序性)。
                例如:操作A先行发生于操作B,其实就是说在发生操作B之前,操作A产生的影响能被操作B观察到,"影响"包括修改了内存中共享变量的值、发送信息、调用方法等。
 
   java内存模型下一些"天然的"先行发生关系,在代码中直接使用。如果两个操作之间的关系不在此列,并且无法从下面规则推导出来的话,它们就没有顺序行保证,
       虚拟机可以对它们随意地进行重新排序。
    
   以下规则一律暂时在一个线程(一个方法)的情况下去理解---☆☆☆
    
   第一:程序次序规则(同一个线程,语句控制流):在一个线程内,按照程序代码顺序,书写在前面的操作先行发生于书写在后面的操作。准确的说,应该是控制流顺序而不是程序代码顺序,因为要考虑分支、循环等结构。
   
   第二:管程锁定规则(同步synchronized块):一个unlock操作先行发生于后面对同一个锁的lock操作。这里必须强调的是同一个锁,而"后面"是指时间上的先后顺序。
   
   第三:volatile变量规则():对一个volatile变量的写操作先行发生于后面对这个变量的读操作,这里的"后面"同样是指时间上的先后顺序。
   
   第四:线程启动规则:Thread对象的start()方法先行发生于此线程的每一个动作。
   
   第五:线程终止规则:线程中的所有操作都先行发生于对此线程的终止检测,我们可以通过Thread.join()方法、Thread.isAlive()的返回值等手段检测到线程已经终止执行。
   
   第六:线程中断规则:对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生,可以通过Thread.interrupted()方法检测到是否有中断发生。
   
   第七:对象终结规则:一个对象的初始化完成(构造函数执行结束)先行发生于他的finalize()方法的开始。
   
   第八:传递性:如果操作A先行发生于操作B,操作B先行发生于操作C,那就可以得出操作A先行发生于操作C的结论。
    
   时间上的先后顺序:可以理解为一个线程A在代码层次先调用,另一个线程B在A之后调用,但是具体哪个线程运行,cup说了算。
                     
   总结:1.时间先后顺序与先行发生原则之间基本没有太大的关系,所有我们衡量并发安全问题的时间不要受时间顺序的干扰,一切必须以先行发生原则为准。
         2.先行发生原则有时也会受指令重排序(无关联性代码的先行发生会受指令重排序优化影响,实际指令的先后不确定)

2、线程调度:指系统为线程分配处理器使用权的过程。
   调度方式:1.协同式线程调度:线程的执行时间由线程本身来控制,线程把自己的工作执行完成之后,要主动通知系统切换到另外一个线程上。
             2.抢占式线程调度:每个线程将由系统来分配执行时间,线程的切换不由线程本身决定(java使用的线程调度方式就是抢占式调度)。
            
java内存模型规则(重点关注)
    重点:1.不允许一个线程丢弃它的最近的assign操作,即变量在工作内存中改变了之后必须把该变化同步回主内存。
             验证结果:volatile 修改后立即同步回主内存了
                      普通变量 修改后也会同步回主内存,只是没有volatile操作时是连续的
    
          2.普通变量在线程中只会读取(read、load)一次(主内存到工作内存),每次使用时使用的是工作内存中的数据,不会在每次使用时,都会从主内存刷新此变量到工作内存中
    
             验证结果:1.线程B中对于isNull(isNull是boolean类型);主内存中的值读入到工作内存仅读取了一次,在线程A针对此变量刷新主内存时,线程B无变化(一直使用的是线程B工作内存中的值)
                      2.list.size();在方法中同上
                     修复方法:1在变量上用volatile修饰 2.添加synchronized同步锁  
                                   
3.线程同步的总结规律
    a)执行完同步代码块就会释放对象的锁。
    b)在执行同步代码块的过程中,遇到异常而导致线程终止,锁也会被释放
    c)在执行同步代码块的过程中,执行的锁所属对象的wait()方法,这个线程会释放对象锁,而此线程对象会进入线程等待池中,等待被唤醒。
    d)处于wait状态下的线程,必须等到该锁对象发出notify或notifyAll,才能解除wait状态,否则即便该锁对象已经空闲,也将继续阻塞在wait状态下。
       wait使线程停止运行,而notify使停止的线程继续运行。
       
☆☆☆☆☆
重点:1.synchronized可以保证进入同步方法或同步代码块的每个线程,都看到由同一个锁保护之前所有的修改效果(每调用一次synchronized修饰的方法或者代码块,都会获取一边对内存中最新的数据)  
      2.wait线程,在被唤醒时,会同步刷新线程中的最新数据(相当于此线程又重新执行了一次(所有)数据的读取--主内存到工作内存)
              数据在线程被唤醒时才会先刷新主内存最新数据到工作内存(仅一次).
              
      3.volatile变量,也会在循环变量使用时,及时刷新(疑惑点--按说应该只是刷新自己,但是在实际现象中好像所有循环中的变量都及时刷新了)
            // 如果注释掉volatile变量list.isNull,那么i数据不会刷新(主内存--工作内存)
            // 如果去掉注释,那么if(list.isNull){}还没有调用,但是if(i==50){}却会运行(说明数据刷新了)
           
4.数据竞争:在访问共享的非final类型的域时没有采用同步来进行协同,那么就会出现数据竞争。

疑问 1.当线程已经运行,其中所有的变量已经从主内存读取到工作内存时,在调用synchronized修饰的方法时,是更新线程中所有的变量,还是仅仅更新此锁所涉及的变量?
       答:更新线程中现存的所有变量(每调用一次synchronized修饰的方法或者代码块,都会获取一边对内存中最新的数据)。
     2.当处于wait状态下的线程,等到notify时,解除wait状态时,是更新线程中所有的变量吗?
          答:wait线程,在被唤醒时,会同步刷新线程中的最新数据(相当于此线程又重新执行了一次(所有)数据的读取--主内存到工作内存)
           数据在线程被唤醒时才会先刷新主内存最新数据到工作内存(仅一次).
     3.当多个线程访问共享数据时,如果此数据没有加同步锁,那么产生的数据一定是脏数据?
       答:线程是抢占式,每个线程随时可以切换到另一个线程,因此每个线程一开始读取的数据是随机的(并不是
           本程序中tickets=100,count =0固定的)。
         每个线程在操作上面的数据时,会在不确定时间将其写入主内存。因此其他线程在开启时,拿到的数据是不确定的随机数据。       
-----------------------------------------------------------------    
线程(Thread)(外练互斥,内修可见)

前言:1.java内存模型是围绕着在并发过程中如何处理原子性,可见性和有序性这个3个特征来建立的。
        原子性(Atomicity):由java内存模型来直接保证的原子性变量操作包括read、load、assign、use、store、和write,我们大致可以认为基本数据类型的访问读写具备原子性,
                           更大范围的原子性保证,java内存模型还提供了lock和unlock操作来满足,反映到java代码其实就是-->synchronized关键字,因此在synchronized块之间的操作也具备原子性。
                           
        可见性(Visibility):是指当一个线程修改了共享变量的值,其他线程能够立即得知这个修改。
                            java内存模型是通过在变量修改后将新值同步回主内存,在变量读取前从主内存刷新变量值这种依赖主内存作为传递媒介的方式来实现可见性的。
                            无论是普通变量还是volatile变量都是如此。
                            
                            普通变量与volatile变量的区别:volatile的特殊规则保证了新值能立即同步到主内存,以及每次使用前立即从主内存刷新。因此,可以说volatile保证了多线程操作时变量的
                            可见性,而普通变量则不能保证这一点。
                            
                            synchronized和final也保证可见性:
                               synchronized:它的可见性是由"对一个变量执行unlock操作之前,必须先把此变量同步回主内存中(执行store、write)"这条规则获得的。
                               final:被final修饰的字段在构造器中一旦初始化完成,并且构造器没有把"this"的引用传递出去,那在其他线程中就能看见final字段的值。
                               
        有序性():java程序中天然的有序性可以总结一句话:如果在本线程中观察,所有的操作都是有序的;如果在一个线程中观察另一个线程,所有的操作都是无序的。
                                                        前半句是指线程内表现为"串行的语义",后半句是指"指令重排序"和"工作内存与主内存同步延迟"现象。
                  synchronized和volatile保证有效性:
                      volatile:禁止指令重排序
                      synchronized:"一个变量在同一时刻只允许一条线程对其进行lock操作"这条规则获得的。
                                    这条规则决定了持有同一个锁的两个同步块只能串行地进入。
                        
前言:1、进程的介绍
      2、多线程的创建方式? 1.继承Thread 2.实现Runnable 3.实现Callable
      3、多线程时异常情况   结束它所在的线程
      4、线程的状态图
      5、线程安全问题
      6、等待唤醒机制
      7、多线程细节
      8、同步与Lock/condition的各自用法,控制线程通信
         使用阻塞队列(BlocakingQueue)控制线程通信
         线程调度(Timer类的应用,单线程):定时器,1.构建timer对象(查构造方法)2.执行timer的相关(schedule)方法,进行任务调度。
                                  注:使用Timer执行任务调度时,所有的任务串行执行。
      9、建议在使用新线程时,优先考虑线程池中来获取新线程(Executors工厂类)
      10、ForkJoinPool(拆分任务,把大任务分解成一个个小任务,具体使用API)
      11、ThreadLocal(线程相关安全类):是Sun公司提供的一个类,此类具备这样的一种机制,能将某个对象绑定到当前线程,也能够从当前线程获取某个对象。

1、进程|线程的介绍?
    进程:正在执行的程序,其实就是应用程序在内存中运行的那片空间,每个应用程序对应一个进程。
    线程:进程中的一个执行单元,负责进程中程序的运行,一个进程至少要有一个线程,一个进程中是可以有多个线程的。
    多线程的特点:可以实现多部分程序同时执行。简称:并发
    
    多线程的使用可以合理使用cpu的资源,如果线程过多会导致性能降低。
    cpu处理程序时是通过快速切换完成的,在我们看来好像随机一样,在某一个时刻,只能有一个程序在运行(多核除外)。
    
    java JVM启动后,必然有一个执行线程从main方法开始,一直执行到main方法结束,这个线程在java中称之为主线程。

2、多线程的创建方式?
    1.继承Thread类(查看API为主)
      1.1 定义一个类继承Thread
      1.2 重写run方法
      1.3 创建子类对象,就是创建线程对象
      1.4 调用start方法,开启线程并让线程执行,同时还会告诉jvm去跳用run方法。
         
     例:class PersonThread extends Thread {
             
             // 重写run方法
             public void run(){
              // 线程中要运行的内容
             }
        }
      下面代码会创建一个线程并启动
        PersonThread tt = new PersonThread(); // 线程对象
        tt.start(); // 开启线程,在主线程之外,开辟一个新的线程,执行run();

    2.实现Runnable接口
      2.1 定义类,实现Runnable接口 (1.避免了继承Thread类的单继承局限性 2.解耦)
      2.2 覆盖接口中的run方法,将线程任务代码定义到run方法中
      2.3 创建Thread类的对象(只有创建Thread类的对象并且调用此对象的start()方法,线程才会创建新的线程)
      2.4 将Runnable接口的子类对象作为参数传递给Thread类的构造函数(看源码-->如右)  public Threaad(Runnable run){                                                                              
      2.5 调用Thread类的start方法开启线程                                                this.run = run;
                                                                                   }
     例:class PersonRun implements Runnable {                                      public void run(){
              // 重写run方法                                                         if(run!=null){
             public void run(){                                                         run.run();
              //  任务代码                                                           }
             }                                                                     }
        }
        
        PersonRun run = new PersonRun(); //线程任务,创建Runnable子类对象
        Thread t = new Thread(run);      //线程对象,接受Runnable接口作为参数
        t.start(); // 开启线程,在主线程之外,开辟一个新的线程,执行run();

    3.实现Callable接口
      3.1 创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,并且该call()方法有返回值
      3.2 创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该FutrueTask对象封装了该Callable对象的call()方法的返回值
      3.3 使用FutureTask对象作为Thread对象的参数,创建并启动新线程
      3.4 调用FutureTask对象的get()方法来获得子线程执行结束后的返回值

     例:class ThirdThread implements Callable<Integer>{ // Callable有泛型限制,接口里的泛型形参类型与call()方法返回值类型相同
             public Integer call(){
                 线程执行体,任务代码
                 return 12;
             }
        }
         
         ThirdThread rt = new ThirdThread();// 创建Callable对象-->线程任务
         FutureTask<Integer> task = new FutureTask<Integer>(rt);//包装Callable类
         new Thread(task,"有返回值的线程").start();
         task.get();//获取线程返回值,该方法将导致主线程被冻结,知道call()方法结束并返回为止。
            
    注:1.线程对象调用run方法和调用start方法区别?
             t.run(); 仅仅是对象调用方法,没有开启线程
          t.start(); 调用start开启线程,并让jvm调用run方法在开启的线程中执行
          
        2.多线程执行时,在栈内存中,其实每一个执行线程都有一片自己所属的栈内存空间,进行方法的压栈和弹栈。
        3.当执行线程的任务结束,线程自动在栈内存中释放,当所有执行线程都结束了,进程就结束了。
        4.自定义线程需要执行的任务都定义在run方法中,因为Thread类已经定义了线程任务的位置(run方法),只要在位置中定义任务代码即可。
 
        
3、多线程时异常情况---☆☆☆
    1.java当多线程时,线程发生异常情况,此异常会结束它所在的线程,并抛出异常(如果此异常没有try捕获,那么就不会有异常日志)
      Android当多线程时,线程发生异常情况,如果没有作出处理,那么所在的线程所在的应用结束。

4、线程的状态图        
 
                                                   
                                                  |-------------------|    
                                                  |   临时阻塞状态    |            
                                                  | 具备cpu的执行资格 |            
                                                  | 不具备cpu的执行权 | ↖            
                                                ↗|-------------------|   ╲
                                              ╱          |↑                ╲
                                            ╱            ||                  ╲    notify()唤醒
                                          ╱              ||                     ╲
                                        ╱                ||                       ╲  time over
                                      ╱            得到  ||  yield()或               ╲
                                       ╱            cpu资源 || 失去cpu资源                 ╲
                                  ╱                      ↓|                               ╲
      |--------------|          ╱                |-------------------|                      ╲  |--------------------|
      |   被创建     | start()╱                  |     运行状态      |   sleep(time)/wait()   ╲|    冻结状态        |
      | new Thread();| ------------------------>  | 具备cpu的执行资格 | <----------------------->| 释放了cpu的执行资格|   
      |--------------|                            | 具备cpu的执行权   |   time over/notify()唤醒 | 释放了cpu的执行权  |
                                                  |-------------------|                          |--------------------|
                                                           |
                                                           | run结束                                                   
                                                           | stop();
                                                           ↓ 异常
                                                  |-------------------|
                                                  |      死亡状态     |
                                                   |-------------------|

     注:1.start()新建线程,具备cpu执行资格,等待cpu的执行权或者直接就获得了zpu的执行权。
         2.sleep(time)释放了cpu的执行权,同时也释放了执行资格(至少在time时间内),只有获得了cpu执行资格(先),其次就是cpu的执行权。    
         3.判断当前线程的状态,看执行资格和执行权。                                          
                                                  
5、线程安全问题
    1.问题产生的原因?
      答:1.多个线程在操作共享的数据(线程任务中在操作共享的数据)
          2.线程任务操作共享数据的代码有多个(运算有多个---且都非原子操作)
      解决思路:只要让一个线程在执行线程任务时将多条操作共享数据的代码执行完,在执行过程中,不要让其他线程参与运算。

    2.java对于线程安全问题解决方式
      答:同步锁(synchronized--锁对象和锁监视器方法,是绑定在一起的。
                 Lock锁跟Condtion监视对象)    
      
        格式:synchronized(obj){ // obj 锁对象                同步函数  public synchronized void say(){         
                  obj.wait(); // 锁对象上的监视器方法                        // 同步代码
                  obj.notigy();                                         }
              }                                               static同步函数...
              注:锁跟监视器方法时绑定在一起的。              注:同步函数使用的锁是this,static同步函数使用的锁是字节码文件对象(类名.class)
            
            
              Lock --锁对象(JDK1.5提供,看文档学习,此处只记载特性)
              Lock lock = newReentrantLock();// 锁对象
              Condition con1 = lock.newCondition();//获得锁上的监视器方法
              Condition con2 = lock.newCondition();//一个锁对象可以关联多个监视器对象
              
                例如: 生产者                                       消费者
                      con1.await();//等待                        con2.await();
                      con2.signal();/唤醒消费者一个线程          con1.signal()//唤醒生产者一个线程
                     
              注:Lock锁可以组合多组Condition监视器方法
              
      (对象-obj/Lock):它如同锁,持有锁的线程可以在同步代码块中执行,在执行过程中,即使丧失了cpu执行权,其它线程也无法执行此同步代码块,只有等待持有此锁(对象)的线程
                      执行完成,释放了锁,其它线程才可以操作执行(同步可以有多个,如果锁一样,同样也只能有一个线程执行)
              
       同步好处:解决了多线程安全问题
           弊端:1.降低了程序的性能(多个线程需要额外判断,较为消耗资源)
                 2.当线程任务中出现了多个同步(多个锁)时,如果同步中嵌套了其他同步,这是容易引发一种现象:死锁
                   例:synchronized(obj){
                           synchronized(this){
                           }
                       }
                       synchronized(this){
                           synchronized(obj){
                           }
                       }
                       
       同步前提:必须保证多个线程在同步中使用的是同一个锁。
           
       如何发现问题?
        答:1.既然是多线程问题,那么一定发生在线程任务内(明确运行的代码)
            2.明确共享数据,任务代码中是否有共性数据。
            3.明确是否对共性数据进行了多次操作或者多次运算。            
                                 
6、等待唤醒机制                                                  
    wait();会让线程处于等待状态(释放了cpu的执行权、执行资格,此线程持有的锁),其实就是将线程临时存储到了线程池中。                                                  
    notify();会唤醒线程池中任意一个等待的线程(如果没有,则此方法空叫一此)                                  
    notifyAll();会唤醒线程池中所有的等待线程。                                              
    
      注:这些方法必须使用在同步中,因为要标识wait,notify等方法所属的锁,同一个锁上的notigy(),只能唤醒该锁上被wait的线程
          wait(),notify()等方法所有调用的对象,必须跟同步的锁(对象)一致.    
                                                  
      为什么这些方法定义在object类中?
       答:锁可以是任意的对象,而所有对象的超类是Object    
            
     

    JDK1.5提供加锁新的对象Lock(主要是效率大大提升)
    Lock接口:提供了一个更加面向对象的锁,在该锁中提供了更多的显示的锁操作
           lock();//获取锁
           unlock();//释放锁
    将原来多生产多消费的同步换成Lock锁,就是将旧锁换成新锁,而新锁与之配套的监视器方法,将其封装到了一个Condition对象中。
           await();
           signal();
           signalAll();
    将所有的监视器方法替换成Condition(此时实现的功能与老锁实现的功能一样--效率低)
      解决思想:同一个锁,可以关联多个监视器对象(这样即保证了多线程当中只有一个线程持有锁,又可以解决让生产者只唤醒消费者,消费者只生产者,从而提供效率)
    
    
7、多线程细节
    1.sleep方法和wait方法异同点是什么?
      相同点:让线程处于冻结状态
      不同点:1.sleep必须指定时间
                wait可以指定是,也可以不指定时间
              2.sleep时间到,线程处于临时阻塞状态或者运行状态
                wait如果没有指定时间,必须要通过notify或notifyAll唤醒
              3.sleep不一定定义在同步中
                wait必须定义在同步中
              4.都定义在同步中
                线程执行到sleep,不会释放锁(只释放了cpu执行权和执行资格)
                线程执行到wait,会释放锁(释放了cpu执行、执行资格、线程持有的锁,三者都释放了)
                
    2.线程如何停止呢?
       stop方法过时,看API文档发现,只有线程结束,线程才会停止。
       线程结束:就是让线程任务代码执行完,run方法结束。
                 run方法中通常都定义循环,只要控制循环就可以了
     注:万一线程在任务中处于冻结状态,怎么停止?
         查阅APIstop方法的描述,发现提供了一个解决方法,如果目标线程等待很长时间,则应使用interrupt方法来中断该线程,所谓的中断并不是定制线程
         interrupt的功能是:将线程的冻结状态清除,让线程恢复到运行状态(让线程重新具备cpu的执行资格),因为是强制性的所以会有异常发生,可以在catch中
         捕获异常,在异常处理中,改变标记让循环结束,让run方法结束。
    
    3.守护线程:后台线程,一般创建的都是前台线程---setDaemon(Boolean on)
          前台后台线程运行时都是一样的,只有结束的时候有些不同,前台线程要通过run方法结束,线程结束。
            后台线程也可以通过run方法结束,线程结束,还有另一中情况,当进程中所有的前台线程都结束了,这时无论后台线程处于什么样的状态,都会结束,从而进程结束。(进程结束依赖的都是前台线程)
      后台线程:前台线程创建的子线程默认是前台线程,后台线程创建的子线程默认是后台线程。
        -->将某个线程设置为后台线程,必须在该线程启动之前设置(setDaemon(true)必须在start方法之前调用)
      
    4.线程优先级
       用数字标识的(1--10)setPriority(int i)方法,设置优先级,其中默认的初始优先级是5,最明显的三个优先级1,5,10
    
    5.线程组(ThreadGroup):可以通过Thread的构造函数明确新线程对的所属的线程组
             好处:可以对多个同组线程,进行统一的操作
               默认都属于main线程组
    
    6.常用方法
       join()方法:等待该线程终止。
          例:在主线程中,其他线程调用此方法,则主线程释放执行权,执行资格,并处于冻结状态。
              什么时候恢复?等待调用此方法的线程执行完。
          应用场景:临时加入一个运算的线程,让该线程运算完,程序才会继续执行。
          
       yield()方法:线程临时暂停,将执行权释放,让其他线程有机会获取执行(本身也可以抢夺执行权)
       interrupt();
       sleep();
       ...
       查看API文档为主。
    7.开发中,线程的匿名内部类体现(一个子类的实例,运行子类的方法)
    
8、线程池    
    Executors (对象工厂类): 通过此类构建相关线程池对象
    ExecutorService:管理线程池,执行一些异步任务(多线程并发执行)方法:execute(....);submit(.....);
    ScheduledExecutorService(允许多线程并发任务调度):ExecutorService的子类,运行执行一些线程调度(在某些时间间隔内执行某些任务);  
    
    线程池的关闭:shutdown(): 任务完成后关闭
                 shutdownnow(): 立即关闭(不管任务是否完成)

-----------------------------------------------------------------    
集合(Collection接口/Map接口)
    1、集合:为了方便对多个对象的操作和数据的存储,容器的一种。
    
    2、集合和数组的区别?
       1.数组的长度是固定的
         集合的长度是可变的
       2.数组中存储的是同一类型的元素,可以是对象类型,也可以是基本数据类型。
         集合存储的都是对象,而且对象的类型可以不一致(集合中存储的都是对象的引用)
        
    3、集合容器的区分方式:每一个容器的数据结构不一样,存储规则不同而已。
    
    4、集合的共性取出方式:
        迭代器(Iterator接口)高级for循环,其实就是增强for循环(集合和数组---只有三个方法用-功能有限)
           在迭代过程中,使用了集合的方法对元素进行操作,会引发java.util.ConCurrentModificationException异常。
            Iterator:在此迭代时,不要使用集合的方法操作元素   
            ListIterator:可以完成在迭代过程中的增删改查动作(List有角标)
          
    5、Collection接口(List和Set集合的超类)
          -->List接口:元素是有序的,元素可以重复(全是围绕索引来定义的)
               list获取元素的方法有两种:1.迭代器 2.for循环+get(int);
                  特有方法:凡是可以操作角标的方法都是该体系特有的方法(get(index));
                  特有迭代器:ListIterator是Iterator的子接口
                     
          -->Set接口:元素是无序的,元素不可以重复。
               set获取元素的方法只有一种:迭代器
    
       List:有序的,带索引的,通过索引就可以精确的操作集合中的元素,元素是可以重复的。
          -->ArrayList:是数组结构(Object类型),长度是可变的(原理是创建新数组+复制数组)
                   查询速度很快,增删较慢,线程不同步
        
          -->Vector:是数组结构,已过时。线程同步,特殊的ArrayList(1.2版本加入的)              
    
          -->LinkedList:双向循环链表结构,线程不同步
                   增删速度很快,查询稍慢
                   可以用于实现堆栈,队列结构
                   堆栈:先进后出   First in Last out     FILO    手枪弹夹
                   队列:先进先出   First in First out    FIFO    排队买票        

       Set:不包含重复元素的集合,不保证添加顺序。
          -->HashSet:哈希表结构(是数组和链表的组合,底层存储借助HashMap),线程不同步
                   保证元素唯一性的方式依赖于元素自身的hashCode()方法和equals()方法,如果元素的hashCode值相同,才会去判断其equals()方法是否为true,
                       如果为true,则表示hashCode值和equals()方法一模一样,则此元素无法存储。
                    查询速度快,保证元素唯一性      

          -->TreeSet:可以对Set集合中的元素进行排序,使用的是二叉树(红黑树)左小右大的原则存储数据(底层借助TreeMap)
                   如何保证元素的唯一性:使用对象本身排序比较方法,结果是否为0,是0视为相同元素不存。
            
             排序方式:1.让元素本身实现Comparable接口,重写comparto()方法,此方法决定你想排序的规则(自定义)
                         返回值 1,-1,0      1 大    -1 小   0相同    元素自然排序
                        2.比较器:在创建TreeSet集合时,在构造函数中指定具体的比较方式。
                          需要定义一个类实现Comparator接口,重写compare()方法.
                
                    两者都存在时,比较器为主(看源码)。
          -->LinkedHashSet:元素不允许重复,保证了添加的顺序(LinkedHashMap)哈希表和链表组合结构,线程不同步。
          -->EnumSet:枚举集合
          -->BitSet: bit集合
                   
         注:HashSet重写hashCode()方法的基本规则
              1.同一个对象多次调用hashCode()方法应该返回相同的值
              2.当两个对象通过equals()方法比较返回true时,这两个对象的hashcode()方法返回相等的值
              3.对象中用作equals()方法比较标准的Field,都应该用来计算hashCode值。
              4.当向HashSet(HashMap)/TreeSet(TreeMap)中添加可变对象时,后面如果修改了HashSet集合中的对象,有可能导致该对象与集合中的其他对象相等(属性内容相等),
               (第一次存储到集合中时,位置已定,后期此对象在变,则集合中存储的位置没变,不会在时时的计算变换位置,因此有可能造成一些混乱)
☆☆☆☆☆       【从而导致集合无法准确访问该对象】--Map集合
                   例如:1.HashMap集合中获取值时,是根据键来获取的,键对象改变时,恰好跟集合中其他存储的对象hashcode(),equals()返回值一样,
                           那么获取的数据是不确定的。(Map在用k去获取v时,会重新判断k---就是会重新调用hashcode(),equals(),确定存储位置,获取对应v)
                         2.TreeMap--Key的存|取都是基于Comparable接口|Comparator接口,而key对应value值
            TreeSet:如果两个对象通过equals()方法比较返回true时,这两个对象通过cmopartto()方法比较应该返回0
            
            建议:HashSet和TreeSet集合中放入不可变对象最好。            
         
      总结:1.集合中存储对象时,通常该对象都需要覆盖hashcode(),equals()方法,同时实现Comparable接口,建立对象的自然排序。
         
    6、Map接口(Map<k,v>)
       1.内部存储的都是键(对象)/值(对象)对
       2.保证键的唯一性,一一对应。
       3.Map集合没有迭代器,取出元素的方式:将Map集合转成单例集合(获取map集合中的所有键(set集合)),在使用单例集合的迭代器获取元素。
         
          -->HashTable:哈希表结构(是数组和链表的组合),线程同步,不允许null作为键和值
                 1.key相同,值覆盖
                 2.保证key的唯一性(hashCode(),equals()方法),不保证添加顺序
                 3.被HashMap替代
        
          -->HashMap:哈希表结构(是数组和链表的组合),线程不同步,允许null作为键和值        
                 1.key相同,值覆盖
                 2.保证key的唯一性,不保证添加顺序
                 3.key的存|取都是基于hashCode(),equals()方法,而key对应value值

          -->TreeMap:数据结构是二叉数,线程不同步,可以对集合中的键进行排序。
                 1.Comparable接口--自然排序
                 2.Comparator接口--比较器
                 3.Key的存|取都是基于Comparable接口|Comparator接口,而key对应value值
                  
          -->Properties:属性集,键和值都是字符串,而且可以结合流进行键值得操作。
                 一般结合IO流使用,通常就用于配置文件的操作(没有泛型,操作的就是字符串)        
    
          -->LinkedHashMap:基于链表+哈希表,可以保证map集合有序(存入和取出的顺序一致)
                 这是成本最高的JDK集合类型        
    
          -->EnumMap:带有enum键的映射,由于已知最大键数量以及内置的enum至int映射,此类运行速度往往高于HashMap    
        
          -->IdentityHashMap:Map的超特殊实现,违背了Map的通用约定:在保证元素的唯一性时,比较的是内存地址(使用==比较,而非hashCode(),equals()方法)
                 这一属性使得IdentityHashMap在各种图遍历算法中大显神通(你可以在IdentityHashMap中轻易的存储已经处理过的节点)
    
          -->WeakHashMap:用于数据缓存的实现,它将所有键都保存于WeakReference,这意味着如果没有指向这些键对象的强引用,这些键就被垃圾回收,另一方面,值却用
                         强引用保存,因此,需要确保不存在从值指向键的引用;或者将值也保存在弱引用中。
               例:m.put(key,new WeakReference(value);
    
    7、1.Collection和Map接口的实现类都在本类中以内部类(此内部类实现了Iterator接口)的形式实现了迭代器对象.
       2.排序接口:Comparable|Comparator     
       3.数组和集合工具类:Collestions|Arrays--查看API文档为主。    
           Collestions:集合框架中用于操作集合对象工具类,都是静态的工具方法。
                  -->1.获取最佳
                     2.对List集合排序,对排序逆序,二分查找
                     3.可以将非同步的集合转成同步的集合
                    
           Arrays:用于操作数组的工具类,都是静态的工具方法
                  -->1.对数组排序,二分查找,数组复制
                     2.数组转成集合(固定大小),不能使用增删等改变长度的方法。
                       数组存储基本数据类型,转成集合,数组对象会作为集合中的元素存在
                       数组存储引用类型,转成集合,数组元素会作为集合中元素存在
                       
    8、Java5新增加Queue体系:代表一种队列集合实现,也是Collection集合框架的一个分支体系
        -->ArrayDeque:基于数组(循环缓冲)的Deque实现,带有头|尾(head|tail)指针,与LinkedList不同,该类没有实现List接口,这意味着除了首尾元素,无法读取其他
                      元素,由于该类生成的垃圾较少,在实现队列和双队列时,该类比LinkedList更加合适;(老数组在扩展是会被抛弃)
    
        -->Stack:后进先出(LIFO)队列,不要在生产代码使用该类(已经废弃)--替代类(ArrayDeque)
        
        -->PriorityQueue:基于priority(优先级)堆的队列,采用自然排序或已知的比较器(Comparator),其中主要方法总是返回队列中最小的余留元素,
                        如果只需要队列中最小的元素,该队列比TreeSet类的其他排序集合更可取。
                       
    9、线程安全的集合类:java.util.concurrent.此包下,查看API
 
-----------------------------------------------------------------
泛型           
    1、泛型定义
       1.编译时的一种类型,JDK1.5出现的特性    
       2.一种安全机制,使用容器时必须明确容器中元素的类型
           1.安全机制
           2.将运行时期的ClassCastException,转移到了编译时期变成了编译失败。
           3.泛型技术,是给编译器使用的技术,在生成的class文件就不带泛型了(泛型的擦除)
           4.避免了强转的麻烦           
    
    2、泛型格式
       1.泛型类:将泛型定义在类上,明确了对象类型,此对象类型由调用者传递。
            例  class luckys<E> {  // 在调用者使用时,明确对象类型,避免转型失败
                  private E object;
                  public E getObject(){
                      return object;
                  }
                  public void setObject(E obj){
                      this.object = obj;
                  }
            }       
        2.泛型方法
           当方法要操作的类型不确定还和类上的泛型不一致时,这时可以将泛型定义在方法上。
               例  public<Q> void show(Q q){}// 泛型方法
                     
              位置:修饰符的后面,返回值得前面
                 
           注:如果方法是静态,还需要使用泛型,那么泛型必须定义在方法上(静态优先对象存在)
               public static <T> void get (){}           
            
        3.泛型接口
            interface Inter<E>{
                void show (E e);
            }        
        
        4.通配符(?)
           当使用泛型类和接口时,传递的具体的类型不确定,可以通过通配符(?)表示一个数据
            -->可以是任意类型的实参
                public void getList(Collection<?> list){}        
            
        5.泛型的限定
           ?extends E : 可以接受E类型或者E类型的子类型----上限
           ? super E :可以接受E类型或者E类型的父类型 ---下限           
            
        6.泛型本省不存在继承
           List<Object> list=new ArrayList<String>();错误
           // 虽然定义正确,但是无法添加数据
           List<? extends Object> list=new ArrayList<String>();正确
               list.add("1"); // 报错,无法添加
               
           List<String> list=new ArrayList<Object>();错误
           // 定义正确,并且可以添加数据
           List<? super String>=new ArrayList<Object>();正确
               list.add("1"); // 无报错,可以添加数据
-----------------------------------------------------------------           
IO    
       
    前言:1.对数据进行持久化操作,java提供了IO技术的操作方式(最终依赖于操作系统)    
          2.数据最终持久化到硬盘上,体现就是文件。

    File(文件类):1.File文件的一些相关认识
                    绝对路径:自己定义文件夹和文件格式,文件名
                                 例如:F:\测试\lucky\1.txt
                                
                    相对路径:则是只传入文件名和文件格式                                     
                              例如:lucky.txt  // 路径为:创建文件所在的当前目录下: D:\lucky\work_cy\luckyMainDemo\lucky.txt              
                                                                                  所在盘、文件根包、项目所在包、项目名、创建的文件                              
                    例如:File file = new File("F:\\测试\\java最新"); //windows 系统 \\
                         1.可以创建此目录或者创建此文件(不存在)
                         2.获取此目录下的所有目录或文件信息(已存在)
                        
                  2.递归遍历文件|文件队列遍历文件
                    1.递归时定义条件控制方向(方向会到终点),否则StackoverflowError 栈溢出,如果递归的目录太高也会StackoverflowError 栈溢出
                    2.文件队列思想
                       1.遍历每一个目录,将其临时存储到队列集合中存储起来
                       2.遍历容器时取到的就是目录,然后对其遍历,并将其移除队列中
                       3.循环遍历这个容器即可。

     编码表:生活中文字和计算机二进制的对应关系表
            1.ascii:一个字节中的7位数可以表示,对应的字节都是正数。
            2.iso8859-1:拉丁码表Latin,用了一个字节的8位,负数。
            3.GB2312:简体中文码表,6,7千的中文和符号,用两个字节表示,两个字节都是开头1,两个字节都是负数。
              GBK:最常用的中文码表,2万的中文和符号,用两个字节表示,一部分文字第一个字节开头是1,第二个字节开头是0
              GB18030:最新的中文码表
            4.unicode:国际标准码表,无论是什么文字,都用2个字节存储,java中的char类型用的就是这个码表,在java中,字符串是按照系统默认的码表来解析
                      的,简体中文版,字符串默认的码表是GBK。
            5.UTF-8:基于unicode,一个字节就可以存储数据的,不要用两个字节存储,而且这个码表更加的标准化,在每一个字节头加入了编码信息(api文档)        
       
         文字 ------> 二进制:编码
         二进制 ------> 文字:解码        

    字节流:操作的是字节数组byte[];
    字符流:操作的是字符数组char[];
    
    字符串必然涉及到编|解码(包括英文和其他文字)
    
    缓冲区的原理(更进一步的封装):
       1.使用了底层流对象从具体设备上获取数据,并将数据存储到缓冲区中的数组内
       2.通过缓冲区方法,来获取缓冲区的数据
       3.如果用read()方法读取字符数据,并存储到另一个容器中,直到读取到了换行符,另一个容器的临时存储的数据转成字符串返回,就形成了readLine()功能。
       
    装饰涉及模式:在不必改变原类文件和使用继承的情况下,动态的扩展一个对象的功能
       设计原则:多用组合,少用继承
       解决问题:给一组类增加功能,避免继承的臃肿,提供灵活
       注意:装饰类和被装饰类必须所属于同一个体系,通常装饰类都会提供构造函数接受被装饰类对象,装饰类通常不单独存在
       
       例如:IO中BufferedReader|BufferedWriter都是使用此类模式

    键盘输入:system.in
    键盘录入:BufferedReader buff = new BufferedReader(new InputStreamReader(System.in));
        
1、字节流(总体就是JVM调用的系统的一些资源来操作,所有要关闭这些资源)        
   
    InputStream         输入流(所有类的超类)       程序(内存) <---------- 文件(本地盘,持久层数据,网络数据...)
    OutoutStream        输出流(所有类的超类)       程序(内存) ----------> 文件(本地盘,持久层数据,网络数据...)
      |-->抽象类,具体使用具体额实例类,每个实例类特点不同(重点查看API)       
        
    IO流异常处理,如下(主流写法):
           File file = new File("D:\\lukcy\\1.txt");
            FileOutputStream fos = null;
                try{
                    fos = new FileOutputStream(file);//文件字节流,每次都会重新创建一个文件,并且覆盖掉原来的,如果想在原文件追加内容,需要加true(查看API)
                    String temp = "ad";
                    byte[] bt = temp.getBytes();
                    fos.write(bt); // 写入到文件中
                }catch(IoException e){
                    //自定义处理方式
                }finally{
                    if(fos != null){
                        try{
                           fos.close();
                        }catch(IoException e){
                           thorw new RuntimeException();
                        }
                    }
                }           
           
2、字符流(特殊的字节流)       
    Reader         输入流      程序(内存) <---------- 文件     读取字符:read();
    Writer           输出流      程序(内存) ----------> 文件     写入字符: write();
     |-->抽象类,具体使用具体额实例类,每个实例类特点不同(重点查看API)

    例:FileReader:底层使用的是FileInputStream,有默认的编码表,可以把字节转成字符.  字节读取流+默认编码表
        FileWriter:底层使用的是FileOutputStream。字节写入流+默认编码表

    BufferedReader;一次可以从缓冲区取一行,原理看源码
    PrintWriter:允许一次写一行,允许自动刷新并且带缓冲区。
    BufferedWriter:不建议使用。

3、Io流规律的总结(四个明确)
    明确一:要操作的数据是数据源还是数据目的
           源:InputStream     Reader
         目的:OutputStream    Writer
        
         先根据需求明确要读,还是要写        

    明确二:要操作的设备上的数据是字节还是文本呢
           源:                   目的:
         字节:InputStream         字节:OutputStream
         文本:Reader               文本:Writer
       
         明确具体的体系上

    明确三:明确数据所在的具体设备
           源设备:                   目的设备:
             硬盘:文件File开头             硬盘:文件File开头
             内存:数组,字符串            内存:数组,字符串
             键盘:System.in               键盘:System.out
             网络:Socket                  网络:Socket
            
              完全可以明确具体要使用哪个流对象
      
    明确四:是否需要额外功能呢?
           额外功能: 1.需要转换吗?  InputStreamReader|OutputStreamWriter
                      2.高效吗? 缓冲区对象--BufferedXXX
                      3.有多个源(字节流)吗? 序列流(SequenceInputStream)--数据合并的流对象
                      4.对象需要序列化吗? ObjectInputStream|ObjectOutputStream
                      5.需要操作基本类型数据保证字节原样性吗? DataOutputStream|

    数据合并的流对象(SequenceInputStream):
     1.读取配置文件,判断碎片文件目录中是否存在(properties文件),使用过滤器完成
     2.获取配置文件,读取配置文件中的信息
     3.合并文件
     大体思想如此,这种切割时有配置文件,另一种切割合并不需要配置文件,在每个文件尾处标明要合并的下一个文件名,也可以实现(这个复杂)
    
4、使用场景
    1.将封装了数据的对象进行持久化(保存到硬盘文件,装有对象的文件,扩展名为lucky.object)
       对象Person(属性name,age),此对象必须实现java.io.serializable接口(标记接口,用于启动类的序列化功能)    
       往硬盘写数据,进行持久化,需要io技术。输出流.FileOutputStream
       在字节输出流中按名称规律在api找到一个子类ObjectOutputStream
       在基础流对象上使用额外功能(功能流,都是基于一个基础流而进行的额外功能)

    2.读取已有的对象文件,并获取对象中的数据
       FileInputStream底层流获取字节数据
       用ObjectInputStream功能流,对用ObjectOutputStream写入的基本数据和对象进行反序列化
       再给对方数据时,Person.class文件和Person.object文件一同给,少一个都无法获取到数据

     序列化接口的作用:没有方法,不需要覆盖,是一个标记接口,为了启动一个序列号功能。
           唯一作用:给每一个需要序列化的类都分配一个序列版本号,这个版本号和该类相关联
                    1.静态数据是不会序列化的
                    2.对于一个非静态的数据也不想序列化,需要关键字来修饰(transient-瞬态,只能内存化,不能持久化),此关键字只用在此处,了解为主                    

    3.a:字节流的write()方法,只将一个整数的最低字节写入到目的地
         例如:353    0000000 0000000 0000001 01100001  只写入后8位
              如果希望写一个整数到目的,整数的表现形式不变,可以将整数转成字符串编程字符数组写入目的地。
              可以使用有额外功能(保证数据值的表现形式):PrintStream 流---底层其实也是将数据转成字符串在写入,保证数据值的表现形式,最终都是转成了字节数组,已经封装。
    
      b:保证数据值字节原样性不变:DataOutputStream|DataItputStream        
      c:源和目的都内存的读写过程
          字节流:ByteArrayInputStream|ByteArrayOutputStream
          字符流:CharArrayReader|CharArrayWriter
                  StringReader|StringReader
        原理:通过流的read,write方法对数组以及字符串进行操作。关闭这些流都是无效的,因为并未调用系统资源,不需要抛出IO异常。

      d:对文件进行读|写的操作,想从那里读就从那里读,想从那里写就从那里写
        RandomAccessFile:IO流工具类,不属于IO体系,即能读有能写
        注意:随机读写,数据需要有规律,每次写入的数据字节长度最好一样,方便控制角标(底层是数组在存储数据)
           局限性:1.只能操作文件
                  2.没有特定需求,一般用不到此类

-----------------------------------------------------------------           
GUI(图形用户界面)简单了解
    1.GUI:Graphical User Interface       图形用户接口
      GLI:Command line User Interface    命令行用户接口
    
      java为GUI提供的对象都在java.awt和java.x.swing两个包中
      java.wat:抽象窗口工具,需要调用本地系统方法实现功能,属重量级控件(跟系统耦合相当紧密)
      java.x.swing:图形界面系统,完全由java实现,增强了移植性,属轻量级控件(开发已此为主)
    
    2.事件监听机制
      a.事件源(组件)    
      b.事件(Event)
      c.监听器(listener)
      d.事件处理(引发事件后处理方式)
    
-----------------------------------------------------------------           
网络编程  IO+网络(java.net包)    
    1、网络模型
        OSI(Open System InterConnection 开放系统) 参考模型    7层
        TCP/IP 参考模型  4层
                          应用层:http是应用层
                          传输层:UDP/TCP  负责数据的传输和链接的建立
                          网际层:加IP地址
                          主机至网络层:硬件设备把数据发送
    
    2、网络通信要素
        IP地址    端口号    传输协议
    
        IP地址:InetAddress     最大为 255
               网络设备中的标识      192.168.1.23  局域网
               不易记忆,可用主机名
               本地主机地址:127.0.0.1   主机名:localhost   
                       ping 127.0.0.1 通,则网卡没有问题
            
             注:域名解析:1.www.baidu.com 先找本地hosts此文件,键值对保存域名和IP
                           2.本地hosts文件没有会找DNS服务器,返回给本地浏览器在用IP去访问
      
        端口号:用于标识进程的逻辑地址,不同进程的标识
                有效端口号:0至65535 ,其中0至1024系统用      
    
        传入协议:通讯的规则
                 常见协议:TCP,UDP  ---数据包:数据,(发送端)源的IP和端口,(接受端)目的的IP和端口
                 UDP:1.将数据以及源和目的封装成数据包中,不需要建立链接
                      2.每个数据包的大小限制在64K内
                      3.因无连接,是不可靠协议
                      4.不需要建议链接,速度快
                    例:本地电脑 MyUDPSend|MyUDPRece
                                 DatagramPacket(数据包)|DatagramSockey(socket)
                                        
                 TCP:1.建立链接,形成传输数据的通道
                      2.在链接中进行大数据量传输
                      3.通过三次握手完成链接,是可靠协议
                      4.必须建立链接,效率会稍低
         
                    例:MyTcpClient|MyTcpServer 最基本通信
                  
                   注意:TCP是发不了广播的
    
        Socket:1.Socket就是为网络服务提供的一种机制
               2.通信的两端都有Socket
               3.网络通信其实就是Socket间的通信
               4.数据在两个Socket间通过IO传输
    
    3、最常见的客户端和服务端
       客户端:浏览器--内置了客户端,可以解析服务端返回的固定格式的数据(大部分数据格式)
       服务端:Tomact
       
       访问方式:先提:Tomact服务器开启   Tomact目录webapps/自己的程序名称/具体资源
       浏览器:输入http:///127.0.0.1:8080/自己的程序名称/具体资源名称
       简单了解:最好买本相关的书,此处介绍原理:
       
       浏览器:http请求协议,内置了客户端
       消息内容:http的请求消息:请求头+请求体,中间有空行
       
       请求头:
              GET/Myweb/1.html  Http/1.1          ----请求行;请求方式 访问资源的路径;http协议版本 1.1|1.0 两个版本
              Accept:image/gif,image kjpeg,image/x-xbitmap,image/gif,application/vnd.ms-ponerpoint,*/*   ----浏览器支持的解析,每个浏览器支持的大致相同,也有不同,如果是不支持的,就不解析了,而下载(已文件的方式下载)
              Accept-Language:zh-cn   ----支持的语音
              Accept-EnCoding;gizp,deflate  ----支持的压缩封装方式,服务器可以将大数据压缩成浏览器支持的方式,发送过来,浏览器在本地解压缩(好处:节省流量,传输速度快)
              User-Agent;Mozilla/4.0 (compatible;MsIE6.0;Widows NT5.1)  ----用户的相关信息
              Host:127.0.0.1:8080   ----访问的主机和端口号            
              Connection:keep-Alive  ----链接:继续保持
         空行:
       请求体:
       
            
       Tomact服务器返回给浏览器的消息:Http的应答消息
       应答头:
              Http/1.1 200 ok  ----应答行 http协议版本  应答状态码(状态码一一对应,200代表成功)
              Server:Apache-Coyote/1.1
              Accept-Randes:bytes
              Etag:W/"467-1374891778953"
              Last-Modified:Sat,27 JUl 2013 02:22:58 GMT   ----文件最后一次修改的日期
              Content-Type:text/html   ----内容的类型
              Content-Length:467       ----数据的长度467个字节
              Date:sun,01sep 2013 07:06:09 GMT
              Connection:close
         空行:
       应答体:请求的数据
       
       
       1.http1.0和1.1的区别?
          1.0 一次链接只能有一次请求,断开,在重新连接收到数据在断开...
          1.1 一次链接多次请求,建立链接,获得所有请求的资源        
       
       2.URL(对象):用于解析url地址,内部封装好了Socket对象
                  构成:协议+资源地址+端口+请求资源字符串
         UKLConnection(对象):获取url的链接,其实是获取了Socket对象IO流来操作数据       
       
       3.常见的网络架构
          C/S:client/server       ---维护较为麻烦
              特点:1.程序需要开发客户端和服务端
                   2.将部分运算转移到客户端来完成,减轻服务端的压力
          
          B/S:browser/server
              特点:1.程序只需要开发服务端,客户端使用系统已有的浏览器即可
                    2.维护简单,只要维护服务端
                    3.所有的运算都在服务端

-----------------------------------------------------------------           
反射(Class,字节码文件对象只有一份---唯一性--class加载机制)
    前言、1.反射技术:动态的获取指定的类以及动态的调用类中的内容
          2.反射技术的出现大大提高了程序的扩展性
          
     Class对象:包含了与类有关的信息,每个类对应的都只有一个Class对象,Class对象就是用来创建类的所有的常规对象的。
            所有的Class对象都属于Class类
     
      
    1、获取字节码(Class)文件对象的方式:
       1)通过Object类中的getClass()方法,调用某个对象的getClass()方法,该方法将会返回该对象所属类对应的Class对象。
            例:   Class  person = new Person().getClass();
               虽然通用,但是前提必须有指定类,并对该类进行对象的创建,才可以调用getClass()方法。          

       2)使用任意数据类的一个静态成员Class(属性),所有的数据类型都具备的一个属性,调用某个类的class属性来获取该类对应的Class对象
            例:   Class  person = Person.class;
               虽然不用new对象,但是,还需要使用具体的类(必须知道类名),如果有某名,建议用此方法(不会初始化Person类(静态初始化))

       3)使用Class类的forName(String className)静态方法,字符串参数的值为某个类的全限定类名(必须是完整的包名),此方法有重载,具体查看API
            例:   Class  person = Class.forName("Myclass.lucky.Person");
                此方法通过给定的全定类名,加载对应的字节码文件(.class),并封装成字节码文件对象Class(会初始化对应的类-->静态初始化)

    2、如何获取对象(Object)
       1)使用Class对象的newInstance()方法来创建该Class对象对应类的实例,这种方式要求该Class对象的对应类有默认的构造器,
          执行此方法实际上是利用默认构造器来创建该类的实例
             例:  Object object = person.newInstance();
 
       2)先使用Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建该Class对象对应类的实例,通过这中方式
          可以选择使用指定的构造器来创建实例。
             例:  Constructor  ct = person.getConstructor(String.class,int.class)
                     Object object = ct.newInstance("张三",22);                   
    
          如何获取字段/方法?
            需要知道字段/方法的名字,得到字段/方法对象在去赋值或调用(查API)
            getxxx:获取都是类中公共的成员
            getDeclaredxxx:获取类中已有的成员(全部)。构造器、属性、方法都可以得到--哪怕是私有的。
            
☆☆☆      如果构造器、字段、方法为私用(private)修饰如何创建对象或赋值?
            例: 1.Class person = Class.forName("myclass.Person");
                    // getDeclaredConstructor()此方法获取本类中的构造器(包括私有)    
                 2.Constructor<?> constructor = person.getDeclaredConstructor(String.class,int.class);    
                    // 此方法重点,true:权限修饰符无效
                 3.constructor.setAccessible(true);
                    // 用私有构造器创建对象
                 4.Object object =  constructor.newInstance("张三",22);
    
    
-----------------------------------------------------------------           
枚举类(ENUM)
1、java是一种强类型的语言(每个变量定义时必须有类型)

2、枚举是对java中变量类型的增强
      1)枚举是一个特殊的类型
      2)且可以对变量的类型进行更加严格的限定
      
3、枚举定义
    1)   //Gender为一个特殊的类,此类为枚举类
        public enum Gender {
          //MALE,和FEMAL代表Gender的两个实例
          MALE,FEMALE
        }

        
      例:/**枚举类:通过此类去定义变量*/
         public enum Week {
            SUNDAY("星期日"){
              @Override
               public int get() {
                // TODO Auto-generated method stub
               return 0;
            }
           };
            //构造方法不能为public
            private Week(){
               System.out.println("==week==");
           }
           private String day;
           private Week(String day){
               this.day=day;
           }
           /**实例方法*/
           public String getDay(){
               return day;
           }
           public static void doPrint(){}
           public abstract int get();
           class Inner{}
           static class StaticInner{}
        }

-----------------------------------------------------------------           
正则表达式
    正则表达式:专门用于操作字符串的技术,而且可以简化代码,用于对字符串进行复杂操作,其实底层对应的还是代码
    
    弊端:符号太多,阅读行较差
    
    学习正则,先学习符号:符号规则 JDK文档--java.util.regex.Pattern 类中查找
        
    正则对字符串的常见功能操作(查String方法即可): 1.匹配 2.切割 3.替换 4.获取 ...